diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c36f6ab72..000000000 --- a/.coveragerc +++ /dev/null @@ -1,8 +0,0 @@ -[report] -exclude_lines = - pragma: no cover - if TYPE_CHECKING: - -[run] -branch = True -source = game,pydcs_extensions,qt_ui,resources/tools diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index e74d8c24c..000000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,2 +0,0 @@ -# Black -a47bef1f1336fd264d0b175f4421758339a30acb \ No newline at end of file diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index cf0a4de91..000000000 --- a/.gitattributes +++ /dev/null @@ -1,92 +0,0 @@ -* text=auto -*.pxd text diff=python -*.py text diff=python -*.py3 text diff=python -*.pyw text diff=python -*.pyx text diff=python -*.pyz text diff=python -*.pyi text diff=python -*.db binary -*.p binary -*.pkl binary -*.pickle binary -*.pyc binary export-ignore -*.pyo binary export-ignore -*.pyd binary -unshipped_data/arcgis_maps/ filter=lfs diff=lfs merge=lfs -text - -# https://github.com/alexkaratarakis/gitattributes/blob/master/Common.gitattributes -# Documents -*.bibtex text diff=bibtex -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain -*.md text diff=markdown -*.mdx text diff=markdown -*.tex text diff=tex -*.adoc text -*.textile text -*.mustache text -*.csv text -*.tab text -*.tsv text -*.txt text -*.sql text -*.epub diff=astextplain - -# Graphics -*.png binary -*.jpg binary -*.jpeg binary -*.gif binary -*.tif binary -*.tiff binary -*.ico binary -# SVG treated as text by default. -*.svg text -# If you want to treat it as binary, -# use the following line instead. -# *.svg binary -*.eps binary - -# Scripts -*.bash text eol=lf -*.fish text eol=lf -*.sh text eol=lf -*.zsh text eol=lf -# These are explicitly windows files and should use crlf -*.bat text eol=crlf -*.cmd text eol=crlf -*.ps1 text eol=crlf - -# Serialisation -*.json text -*.toml text -*.xml text -*.yaml text -*.yml text - -# Archives -*.7z binary -*.gz binary -*.tar binary -*.tgz binary -*.zip binary - -# Text files where line endings should be preserved -*.patch -text - -# -# Exclude files from exporting -# - -.gitattributes export-ignore -.gitignore export-ignore -.gitkeep export-ignore \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index 25ea1fdc3..000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: Bug report -description: > - Use for any bug that happens after campaign generation. If the New Game wizard - failed, use the "New Game wizard failed" template instead. -labels: bug -body: - - type: markdown - attributes: - value: > - Before filing, please search the issue tracker to see if the issue has - already been reported. - - type: dropdown - validations: - required: true - attributes: - label: Affected versions - multiple: true - description: > - Select all DCS Liberation versions in which you have observed this bug. - You do not need to test all of them, but the information is useful if - you have it. - - - If you do not see your version listed here you are on an old release - that is not supported, and the bug may already be fixed in a newer - release. Check that the bug still exists in a newer release before - filing. - - - If the bug was found in a development build, select "Development build" - and provide a link to the build in the field below. - options: - - 10.0.0 - - Development build - - type: textarea - attributes: - label: Build information - description: - The build information from the Help -> Report an issue window. - - type: textarea - attributes: - label: Description - description: > - Describe the bug. What went wrong? What did you expect to happen - instead? What steps should we take to reproduce the error? If an error - dialog was shown, include the full text. - validations: - required: true - - type: textarea - attributes: - label: Save game and other files (save game required, bugs without saves will be closed) - description: > - Attach any files needed to reproduce the bug here. **A save game is - required.** Even if it seems unnecessary to you, this is required. - Repro steps that are obvious to you might not be obvious to anyone - else, and it is impossible for us to know what default settings or mods - may be impacting behavior without a save game. Bugs filed without a - save game are very often not reproducible, and those waste scarce - developer time. It is **much** easier for you to attach a save game - than it is for us to recreate your save state by guessing at what you - did. As such, bug reports that do not attach a saved game will be - closed without investigation. Attach the `.liberation.zip` file found - in `%USERPROFILE%/Saved Games/DCS/Liberation/Saves`. - - - Other useful files to include are: - - - The Liberation log file. The log file is located at `/logs/liberation.log`. The log often includes data about - non-fatal errors that could be the root cause of the problem. - - - The `liberation_nextturn.miz` or a track file. This should always be - included for bugs where the mission was generated incorrectly or where - the in-game AI is misbehaving. - - - The `state.json` file for the most recently completed turn, located at - `/state.json`. This file is essential for - investigating any issues with end-of-turn results processing. - - - If reporting an issue that occurred during or after flying the mission - in DCS, the DCS log file found in `%USERPROFILE%/Saved Games/DCS/Logs`. - - - You can attach files to the bug by dragging and dropping the file into - this text box. GitHub will not allow uploads of all file types, so - attach a zip of the files if needed. - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/campaign_update.md b/.github/ISSUE_TEMPLATE/campaign_update.md deleted file mode 100644 index 6e0882ee4..000000000 --- a/.github/ISSUE_TEMPLATE/campaign_update.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Campaign update submission -about: Submit an update to a campaign you maintain. -title: 'Update for ' -labels: campaign-update-submission -assignees: '' - ---- - -This form should only be used for submitted updated miz/json files for campaigns -distributed with Liberation. If you are _requesting_ an update to a campaign, see -https://github.com/dcs-liberation/dcs_liberation/wiki/Campaign-maintenance. If the -campaign has an owner, it will be updated before release. If it does not, you can -volunteer to own it. - -If you are not the owner of the campaign listed on -https://github.com/dcs-liberation/dcs_liberation/wiki/Campaign-maintenance, please start -there. - -Otherwise, delete everything above the line below and fill out the following form. Note: -GitHub does not accept .miz files. You can either rename the file to .miz.txt or add the -file to a .zip file. - ---- - -* Campaign name: -* Files: -* Update summary (optional): \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index d0eca85e3..000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,19 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: FAQ - url: https://discord.gg/PXHA6AXw - about: Check to see if your issue is in the FAQ. - - name: Manual - url: https://github.com/dcs-liberation/dcs_liberation/wiki/ - - name: Feature blocking DCS AI bugs - url: https://github.com/dcs-liberation/dcs_liberation#dcs-bugs - about: > - A list of known DCS bugs that prevent us from improving AI behavior. Check - the list before filing AI bugs here to see if it's something we know about - but cannot fix. - - name: DCS bugs - url: https://forums.eagle.ru/forum/119-dcs-world-27/ - about: > - DCS bugs should be reported against DCS, not here. Occasionally we can add - workarounds for DCS bugs. Use the "Bug report" template if you can suggest - a workaround. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 4176751fa..000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: enhancement -assignees: '' - ---- - -Before filing, please search the issue tracker to see if this feature has already been requested. - -If requesting a DCS AI feature, check If reporting a DCS AI bug, check https://github.com/dcs-liberation/dcs_liberation#dcs-bugs. - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/mod_support.md b/.github/ISSUE_TEMPLATE/mod_support.md deleted file mode 100644 index be6b644cd..000000000 --- a/.github/ISSUE_TEMPLATE/mod_support.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: Mod support request -about: Request Liberation support for new mods, or updates to existing mods -title: Add/update -labels: mod support -assignees: '' - ---- - -* Mod name: -* Mod URL: -* Update or new mod? \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/new-game-bug.yml b/.github/ISSUE_TEMPLATE/new-game-bug.yml deleted file mode 100644 index ef2dda5a3..000000000 --- a/.github/ISSUE_TEMPLATE/new-game-bug.yml +++ /dev/null @@ -1,113 +0,0 @@ ---- -name: New Game wizard failed -description: > - Use for bugs that prevent the "New Game" wizard from completing successfully. - If the wizard completes without issue, use the normal bug report template. -labels: bug -body: - - type: markdown - attributes: - value: > - Before filing, please search the issue tracker to see if the issue has - already been reported. - - - If the bug is not related to campaign generation (the campaign was - created successfully and as expected), use the normal bug report - template instead, as this template will not include the information we - need. We are unable to investigate incomplete bug reports, so they will - be closed and you will be asked to refile. If you're unsure, use your - best guess. Needing to refile is not the end of the world :) - - type: dropdown - validations: - required: true - attributes: - label: Affected versions - multiple: true - description: > - Select all DCS Liberation versions in which you have observed this bug. - You do not need to test all of them, but the information is useful if - you have it. - - - If you do not see your version listed here you are on an old release - that is not supported, and the bug may already be fixed in a newer - release. Check that the bug still exists in a newer release before - filing. - - - If the bug was found in a development build, select "Development build" - and provide a link to the build in the field below. - options: - - 10.0.0 - - Development build - - type: textarea - attributes: - label: Build information - description: - The build information from the Help -> Report an issue window. - - type: input - attributes: - label: Campaign name - description: > - The name of the campaign you selected. If the bug only occurs with a - custom campaign (or modifications to a stock campaign), upload the - campaign file as an attachment to the bug description field. - validations: - required: true - - type: input - attributes: - label: Blue faction - description: > - The name of the blue faction you selected. If the bug only occurs with a - custom faction (or modifications to a stock faction), upload the faction - file as an attachment to the bug description field. - validations: - required: true - - type: input - attributes: - label: Red faction - description: > - The name of the red faction you selected. If the bug only occurs with a - custom faction (or modifications to a stock faction), upload the faction - file as an attachment to the bug description field. - validations: - required: true - - type: textarea - attributes: - label: Modifications to default settings - description: > - Describe any modifications you made to the default campaign generation - settings. - - type: textarea - attributes: - label: Description - description: > - Describe the bug. What went wrong? If an error dialog was shown, include - the full text. - - - Attach any relevant files such as custom campaign files or factions - here. You can attach files to the bug by dragging and dropping the file - into this text box. GitHub will not allow uploads of all file types, so - attach a zip of the files if needed. - - - If possible, also include the save game. If the bug prevented the game - from being generated at all this will not be possible, but if the bug is - that the wizard generated something incorrectly, the save game will help - us see what went wrong. - validations: - required: true - - type: textarea - attributes: - label: Log file - description: > - Attach the Liberation log file. The log file is located at `/logs/liberation.log`. - - - You can attach files to the bug by dragging and dropping the file into - this text box. - validations: - required: true diff --git a/.github/actions/build-app/action.yaml b/.github/actions/build-app/action.yaml deleted file mode 100644 index 232731086..000000000 --- a/.github/actions/build-app/action.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Build Liberation package -description: Assembles the full Liberation application. -runs: - using: composite - steps: - - name: Build client - shell: powershell - run: | - cd client - npm run build - - - name: Build binaries - shell: powershell - run: | - ./venv/scripts/activate - $env:PYTHONPATH=".;./pydcs" - pyinstaller pyinstaller.spec - - - name: Install changelog - shell: powershell - run: | - Copy-Item .\changelog.md .\dist diff --git a/.github/actions/mypy/action.yaml b/.github/actions/mypy/action.yaml deleted file mode 100644 index d4ac95adb..000000000 --- a/.github/actions/mypy/action.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: mypy -description: Type checks Python code. -runs: - using: composite - steps: - - name: mypy game - shell: powershell - run: | - ./venv/scripts/activate - mypy game - - - name: mypy tests - shell: powershell - run: | - ./venv/scripts/activate - mypy tests diff --git a/.github/actions/setup-liberation-js/action.yaml b/.github/actions/setup-liberation-js/action.yaml deleted file mode 100644 index 1408e66c0..000000000 --- a/.github/actions/setup-liberation-js/action.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Liberation JS set-up -description: Sets up the Liberation Javascript environment. -runs: - using: composite - steps: - - name: Set up Node - uses: actions/setup-node@v2 - with: - node-version: "16" - cache: npm - cache-dependency-path: client/package-lock.json - - - name: npm ci - shell: powershell - run: | - cd client - npm ci diff --git a/.github/actions/setup-liberation-python/action.yaml b/.github/actions/setup-liberation-python/action.yaml deleted file mode 100644 index 4d2d78771..000000000 --- a/.github/actions/setup-liberation-python/action.yaml +++ /dev/null @@ -1,21 +0,0 @@ -name: Liberation Python set-up -description: Sets up the Liberation Python environment. -runs: - using: composite - steps: - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: "3.11" - cache: pip - - - name: Install environment - shell: powershell - run: | - python -m venv ./venv - - - name: Install dependencies - shell: powershell - run: | - ./venv/scripts/activate - python -m pip install -r requirements.txt diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index b22175a33..000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,24 +0,0 @@ -Pull requests should be made against the `develop` branch. Any backports -necessary will be handled by the development team. - -Pull requests should be focused on one task. Multiple bug fixes should be -multiple PRs. We cannot merge half a PR, and combined PRs are much more -difficult to review. PRs that do not adhere to this will have their review -delayed. - -Prefer rebase to merge, and squash commits as needed to preserve a readable -commit history. This project maintains linear history in the develop branch, so -we will either rebase or squash your PR when merging. It is much easier for us -if your branch already has a readable commit history (ensure that your commit -subject lines are clear enough to identify the patch in the git log). An -exception to this is made for large PRs that are likely to require multiple -rounds of review; in that case it's easier if you **don't** do this (GitHub -does not preserve the history of old commits, so we cannot filter a PR for only -new changes if a branch is force pushed) and we will squash it when merging. - -New features and bug fixes are usually worth mentioning in the changelog. -Exceptions are fixes for bugs that never shipped (were only present in a canary -build), and changes with no intended user observable behavior, such as a -refactor. If you're comfortable writing the note yourself, add it to -`changelog.md` in the root of the project in the section for the upcoming -release. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 2d6ca0140..000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Build - -on: [push, pull_request] - -jobs: - lint: - uses: ./.github/workflows/lint.yml - - test: - uses: ./.github/workflows/test.yml - - build: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - - name: Set up Python environment - uses: ./.github/actions/setup-liberation-python - - - name: Set up JS environment - uses: ./.github/actions/setup-liberation-js - - - name: Set build number - run: | - [IO.File]::WriteAllLines($pwd.path + "\resources\buildnumber", $env:GITHUB_RUN_NUMBER) - [IO.File]::WriteAllLines($pwd.path + "\resources\gitsha", $env:GITHUB_SHA) - - - name: Build app - uses: ./.github/actions/build-app - - - name: Create archive - run: - Compress-Archive -Path .\dist\dcs_liberation\ -DestinationPath - dist\dcs_liberation.zip - - - uses: actions/upload-artifact@v2 - with: - name: dcs_liberation - path: dist/dcs_liberation.zip diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index 557b9b42d..000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Python lint - -on: workflow_call - -jobs: - black: - name: Black - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - - uses: psf/black@stable - with: - version: ~=23.11 - src: "." - options: "--check" - - mypy: - name: Type checking - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - - name: Set up Python environment - uses: ./.github/actions/setup-liberation-python - - - name: mypy - uses: ./.github/actions/mypy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 4afec82a8..000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Release Pipeline - -on: - push: - tags: ["*"] - -jobs: - lint: - uses: ./.github/workflows/lint.yml - - test: - uses: ./.github/workflows/test.yml - - build: - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - - name: Set up Python environment - uses: ./.github/actions/setup-liberation-python - - - name: Set up JS environment - uses: ./.github/actions/setup-liberation-js - - - name: Finalize build - run: | - New-Item -ItemType file resources\final - - - name: Build app - uses: ./.github/actions/build-app - with: - release: true - - - uses: actions/upload-artifact@v2 - with: - name: dcs_liberation - path: dist/ - - release: - needs: [build] - runs-on: windows-latest - steps: - - uses: actions/download-artifact@v2 - with: - name: dcs_liberation - - - name: "Get Version" - id: version - env: - TAG_NAME: ${{ github.ref }} - run: | - Get-ChildItem -Recurse -Depth 1 - $version = ($env:TAG_NAME -split "/") | Select-Object -Last 1 - $prerelease = ("2.1.1-alpha3" -match '[^\.\d]').ToString().ToLower() - Write-Host $version - Write-Host $prerelease - Write-Output "::set-output name=number::$version" - Write-Output "::set-output name=prerelease::$prerelease" - $changelog = Get-Content .\changelog.md - $last_change = ($changelog | Select-String -Pattern "^#\s" | Select-Object -Skip 1 -First 1).LineNumber - 2 - ($changelog | Select-Object -First $last_change) -join "`n" | Out-File .\releasenotes.md - Compress-Archive -Path .\dcs_liberation -DestinationPath "dcs_liberation.$version.zip" -Compression Optimal - - - uses: actions/create-release@v1 - id: create_release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref }} - body_path: releasenotes.md - draft: false - prerelease: ${{ steps.version.outputs.prerelease }} - - - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./dcs_liberation.${{ steps.version.outputs.number }}.zip - asset_name: dcs_liberation.${{ steps.version.outputs.number }}.zip - asset_content_type: application/zip diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 6dd40fb48..000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Tests -on: workflow_call -jobs: - python-tests: - name: Python tests - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - with: - submodules: true - - - name: Set up Python environment - uses: ./.github/actions/setup-liberation-python - - - name: run tests - run: | - ./venv/scripts/activate - pytest --cov --cov-report=xml tests - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 - - ts-tests: - name: Typescript tests - runs-on: windows-latest - steps: - - uses: actions/checkout@v2 - - - name: Set up JS environment - uses: ./.github/actions/setup-liberation-js - - - name: run tests - run: | - cd client - npm test -- --coverage - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 197ba2a3f..000000000 --- a/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -*.pyc -__pycache__ -build/** -# Sphinx -docs/_build -resources/payloads/*.lua -venv -.DS_Store -.vscode/settings.json -dist/** -/.coverage -/coverage.xml -# User-specific stuff -.idea/ -.env -env/ - -/kneeboards -/liberation_preferences.json -/state.json -/serverconfig.env - -/logs/ -/resources/logging.yaml - -*.psd diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 428235a74..000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,6 +0,0 @@ -repos: - - repo: https://github.com/psf/black - rev: 23.11.0 - hooks: - - id: black - language_version: python3 \ No newline at end of file diff --git a/.readthedocs.yaml b/.readthedocs.yaml deleted file mode 100644 index e88e6c7af..000000000 --- a/.readthedocs.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 2 - -build: - os: ubuntu-22.04 - tools: - python: "3.11" - -sphinx: - configuration: docs/conf.py - -python: - install: - - requirements: docs/requirements.txt diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 778f6d535..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Main", - "type": "python", - "request": "launch", - "program": "qt_ui\\main.py", - "console": "integratedTerminal", - "env": { - "PYTHONPATH": ".;./pydcs" - }, - "preLaunchTask": "Prepare Environment" - }, - { - "name": "Python: Debug", - "type": "python", - "request": "launch", - "program": "qt_ui\\main.py", - "console": "integratedTerminal", - "env": { - "PYTHONPATH": ".;./pydcs", - "CORS_ALLOW_DEBUG_SERVER": "true" - }, - "args": ["--dev"], - "preLaunchTask": "Prepare Environment" - }, - { - "name": "Node: Development Server", - "type": "node", - "request": "launch", - "cwd": "${workspaceRoot}\\client", - "runtimeExecutable": "npm", - "runtimeArgs": [ - "run", "start" - ], - "env": { - "BROWSER": "none" - }, - }, - { - "name": "Python: Make Release", - "type": "python", - "request": "launch", - "program": "resources\\tools\\mkrelease.py", - "console": "integratedTerminal", - "env": { - "PYTHONPATH": ".;./pydcs" - }, - "preLaunchTask": "Prepare Environment" - }, - { - "name": "Fix Layout orientation", - "type": "python", - "request": "launch", - "program": "resources\\tools\\fix_layout_orientation.py", - "console": "integratedTerminal", - "env": { - "PYTHONPATH": ".;./pydcs" - }, - "args": ["resources/layouts/anti_air/S-300_Site.miz"] - }, - ] -} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 84bd2413b..000000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "Prepare Environment", - "type": "shell", - "isBackground": false, - "problemMatcher": [], - "command": "powershell", - "args": [ - "-Command", - "& {if (-not (Test-Path ${workspaceFolder}\\venv)) { python -m venv ${workspaceFolder}\\venv; . ${workspaceFolder}\\venv\\scripts\\activate.ps1; pip install -r requirements.txt; Copy-Item ${workspaceFolder}\\venv\\Lib\\site-packages\\shiboken2\\shiboken2.abi3.dll ${workspaceFolder}\\venv\\Lib\\site-packages\\PySide2 } }", - ], - "group": "build", - "options": { - "env": { - "PYTHONPATH": ".;./pydcs" - } - }, - "presentation": { - "echo": true, - "reveal": "never", - "focus": false, - "panel": "shared", - "showReuseMessage": true, - "clear": false - }, - "runOptions": { - "runOn": "folderOpen" - } - } - ] -} \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index d3ce4df3e..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at khopa.studio@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index d0e863f3a..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,26 +0,0 @@ -First, note that we have a code of conduct, please follow it in all your interactions with the project. - -## Contributing as a non-developer - -* Report bugs by opening issues here on Github. -* Help others users on Discord by answering their questions. -* Raise awareness about the project, by making a video and/or a tutorial. - -Should you report a bug, please use the search bar at the top of the page to see if it has already been reported. -Note that you may need to remove the filter for open bugs if it's something we've recently fixed. - -## Making content for Liberation - -You can create new campaigns : See [campaign creation wiki](https://github.com/dcs-liberation/dcs_liberation/wiki/Custom-Campaigns). -You can also improve existing campaigns. - -You can then submit new campaigns on the "campaigns" channel on Discord, or by making a pull request if you are comfortable with git. - -## Develop new features - -If you want to develop a new feature, we recommend you first open an issue describing the new feature and discuss it with us on Discord before starting development. -However, feel free to work on any existing issue. - -## Pull requests - -Please submit your pull requests on the **develop** branch. We expect a description of its content, and when applicable, a reference to the issue(s) it is resolving. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 02bbb60bc..000000000 --- a/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 43123fb6c..000000000 --- a/README.md +++ /dev/null @@ -1,65 +0,0 @@ -[![Logo](https://i.imgur.com/HJBT4BL.png)](https://shdwp.github.io/ukraine/) - -(Github Readme Banner and Splash screen Artwork by Andriy Dankovych, CC BY-SA 4.0) - -[![Patreon](https://img.shields.io/badge/patreon-become%20a%20patron-orange?logo=patreon)](https://patreon.com/dcsliberation) - -[![Download](https://img.shields.io/github/downloads/dcs-liberation/dcs_liberation/total?label=Download)](https://github.com/dcs-liberation/dcs_liberation/releases) - -[![Discord](https://img.shields.io/discord/595702951800995872?label=Discord&logo=discord)](https://discord.gg/bKrtrkJ) - -[![codecov](https://codecov.io/gh/dcs-liberation/dcs_liberation/branch/develop/graph/badge.svg?token=EEQ7G76K2L)](https://codecov.io/gh/dcs-liberation/dcs_liberation) -[![GitHub pull requests](https://img.shields.io/github/issues-pr/dcs-liberation/dcs_liberation)](https://github.com/dcs-liberation/dcs_liberation) -[![GitHub issues](https://img.shields.io/github/issues/dcs-liberation/dcs_liberation)](https://github.com/dcs-liberation/dcs_liberation/issues) -![GitHub stars](https://img.shields.io/github/stars/dcs-liberation/dcs_liberation?style=social) - -## About DCS Liberation -DCS Liberation is a [DCS World](https://www.digitalcombatsimulator.com/en/products/world/) turn based single-player or co-op dynamic campaign. -It is an external program that generates full and complex DCS missions and manage a persistent combat environment. - -**Note that DCS Liberation does not support the stable release of DCS. We can -only guarantee compatibility with either the open beta or the stable release, -and more people play the open beta. DCS stable _might_ work sometimes, but it's -untested, and we will be unable to fix any bugs unique to stable DCS.** - -![Screenshot](https://user-images.githubusercontent.com/315852/120939254-0b4a9f80-c6cc-11eb-82f5-ce3f8d714bfe.png) - -## Downloads - -Latest release is available here : https://github.com/dcs-liberation/dcs_liberation/releases - -To download preview builds of the next version of DCS Liberation, see https://github.com/dcs-liberation/dcs_liberation/wiki/Preview-builds. - -## DCS bugs - -These DCS bugs prevent us from improving AI behavior. Please upvote them! (But please -_don't_ spam them with comments): - -* [A2A and SEAD escorts don't escort](https://forums.eagle.ru/topic/251798-options-for-alternate-ai-escort-behavior/?tab=comments#comment-4668033) -* [DEAD can't use mixed loadouts effectively](https://forums.eagle.ru/topic/271941-ai-rtbs-after-firing-decoys-despite-full-load-of-bombs/) - -## Bugs and feature requests - -If you need to report a bug or want to suggest a new feature, you can do this on our [bug tracker](https://github.com/dcs-liberation/dcs_liberation/issues). In either case, please use the search bar at the top of the page to see if it has already been reported. Note that you may need to remove the filter for open bugs if it's something we've recently fixed. - -## Roadmap - -Our plans for future releases can be found on our [Projects page](https://github.com/dcs-liberation/dcs_liberation/projects). Each planned release has a Project, and the page for that project has columns for to do, in progress, and done. Items in the Done column are in the [preview build](https://github.com/dcs-liberation/dcs_liberation/wiki/Preview-builds) for that release. Items in the To do column are planned to be added to that release. - -## Resources - -Tutorials, contributors and developer's guides are available in the project's [Wiki](https://github.com/dcs-liberation/dcs_liberation/wiki/) - -## Special Thanks - -First, a big thanks to shdwp, for starting the original DCS Liberation project. - -Then, DCS Liberation uses [pydcs](http://github.com/pydcs/dcs) for mission generation, and nothing would be possible without this. -It also uses the popular [Mist](https://github.com/mrSkortch/MissionScriptingTools) lua framework for mission scripting. - -Excellent lua scripts DCS Liberation uses as plugins: - -* For the JTAC feature, DCS Liberation embeds Ciribob's JTAC Autolase [script](https://github.com/ciribob/DCS-JTACAutoLaze). -* Walder's [Skynet-IADS](https://github.com/walder/Skynet-IADS) is used for Integrated Air Defense System. - -Please also show some support to these projects ! diff --git a/changelog.md b/changelog.md deleted file mode 100644 index 13cff1910..000000000 --- a/changelog.md +++ /dev/null @@ -1,1135 +0,0 @@ -# 11.0.0 - -Saves from 10.x are not compatible with 11.0.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.9.3.51704. -* **[Campaign]** Improved tracking of parked aircraft deaths. Parked aircraft are now considered dead once sufficient damage is done, meaning guns, rockets and AGMs are viable weapons for OCA/Aircraft missions. Previously Liberation relied on DCS death tracking which required parked aircraft to be hit with more powerful weapons e.g. 2000lb bombs as they were uncontrolled. -* **[Campaign]** Track damage to theater ground objects across turns. Damage can accumulate across turns leading to death of the unit. This behavior only applies to SAMs, ships and other units that appear on the Liberation map. Frontline units and buildings are not tracked (yet). - - -## Fixes - -# 10.0.0 - -Saves from 9.x are not compatible with 10.0.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.9.2.49629 Open Beta. (F-15E JDAM and JSOW, F-16 AIM-9P, updated Falklands and Normandy airfields). -* **[UI]** Improved the description of "runway" state for FARPs, FOBs, carriers, and off-map spawns. - -## Fixes - -* **[Flight Planning]** Aircraft from even numbered flights will no longer become inaccessible when canceling a draft package. -* **[UI]** Flight members in the loadout menu are now numbered starting from 1 instead of 0. -* **[UI]** Flight plan paths are now drawn behind all other map elements, fixing rare cases where they could prevent other UI elements from being clickable. - -# 9.0.0 - -Saves from 8.x are not compatible with 9.0.0. - -## Features/Improvements - -* **[Engine]** Support for DCS Open Beta 2.9.0.46801. -* **[Campaign]** Added ferry only control points, which offer campaign designers a way to add squadrons that can be brought in after additional airfields are captured. -* **[Campaign]** The new squadron rules (size limits, beginning the campaign at full strength) are now the default and required. The old style of unlimited squadron sizes and starting with zero aircraft has been removed. -* **[Data]** Added support for the ARA Veinticinco de Mayo. -* **[Data]** Changed display name of the AI-only F-15E Strike Eagle for clarity. -* **[Flight Planning]** Improved IP selection for targets that are near the center of a threat zone. -* **[Flight Planning]** Moved CAS ingress point off the front line so that the AI begins their target search earlier. -* **[Flight Planning]** Loadouts and aircraft properties can now be set per-flight member. Warning: AI flights should not use mixed loadouts. -* **[Flight Planning]** Laser codes that are pre-assigned to weapons at mission start can now be chosen from a list in the loadout UI. This does not affect the aircraft's TGP, just the weapons. Currently only implemented for the F-15E S4+ and F-16C. -* **[Mission Generation]** Configured target and initial points for F-15E S4+. -* **[Mission Generation]** Added a package kneeboard page that shows the radio frequencies, tasks, and laser codes for each member of your package. -* **[Mission Generation]** Added option to generate AI flights with unlimited fuel (enabled by default). -* **[Modding]** Factions can now specify the ship type to be used for cargo shipping. The Handy Wind will be used by default, but WW2 factions can pick something more appropriate. -* **[Modding]** Unit variants can now set a display name separate from their ID. -* **[Modding]** Updated Community A-4E-C mod version support to 2.2.0 release. -* **[UI]** An error will be displayed when invalid fast-forward options are selected rather than beginning a never ending simulation. -* **[UI]** Added cheats for instantly repairing and destroying runways. -* **[UI]** Improved usability of the flight properties UI. It now shows human-readable names and uses more appropriate UI elements. -* **[UI]** The map now shows the real front line bounds. - -## Fixes - -* **[Campaign]** Fixed error when canceling squadron transfer if the current location would be exactly full. -* **[Data]** Fixed the class of the Samuel Chase so it can't be picked for a AAA or SHORAD site. -* **[Data]** Allow CH-47D, CH-53E and UH-60A to operate from carriers and LHAs. -* **[Data]** Added the F-15E's LANTIRN to the list of known targeting pods. Player F-15E flight with TGPs will now be assigned laser codes. -* **[Flight Planning]** Patrolling flight plans (CAS, CAP, refueling, etc) now handle TOT offsets. -* **[Loadouts]** Fixed error when loading certain DCS loadouts which contained an empty pylon (notably the Mosquito). -* **[Mission Generation]** Restored previous AI behavior for anti-ship missions. A DCS update caused only a single aircraft in a flight to attack. The full flight will now attack like they used to. -* **[Mission Generation]** Fix generation of OCA Runway missions to allow LGBs to be used. -* **[Mission Generation]** Fixed AI flights flying far too slowly toward NAV points. -* **[Mission Generation]** Fixed Recovery Tanker mission type intermittently failing due to not being able to find the CVN. -* **[Mission Generation]** Fixed "division by zero" error on mission generation when a flight has an "In-Flight" start type and starts on top of a mission waypoint. -* **[Mission Generation]** Fixed flights not being selectable in the mission editor if fast-forward was used and they were generated at a waypoint that had a fixed TOT (such as a BARCAP that was on-station). -* **[Mission Generation]** Fixed error when planning TARCAPs on the sole remaining enemy airfield. -* **[Mission Generation]** Fixed allocation range for carrier Link 4 datalink. -* **[Modding]** Unit variants can now actually override base unit type properties. -* **[New Game Wizard]** Factions are reset to default after clicking "Back" to Theater Configuration screen. -* **[Plugins]** Fixed Lua errors in Skynet plugin that would occur whenever one coalition had no IADS nodes. -* **[UI]** Fixed deleting waypoints in custom flight plans deleting the wrong waypoint. -* **[UI]** Fixed flight properties UI to support F-15E S4+ laser codes. -* **[UI]** In unit transfer dialog, only list control points that are reachable from the control point units are being transferred from. -* **[UI]** Fixed UI bug where altering an "ahead of package" TOT offset would change the offset back to a "behind package" offset. -* **[UI]** Fixed bug where changing TOT offsets could result in flight startup times that are in the past. -* **[UI]** Fixed odd spacing of the finance window when there were not enough items to fill the page. -* **[UI]** Fixed regression where waypoint altitude changes in the waypoint list screen are applied to the wrong waypoint. -* **[UI]** Fixed regression where waypoint additions in custom flight plans are not reflected until the window is reloaded. - -# 8.1.0 - -Saves from 8.0.0 are compatible with 8.1.0 - -## Features/Improvements - -* **[Engine]** Support for DCS 2.8.6.41363, including F-15E support. -* **[UI]** Flight loadout/properties tab is now scrollable. - -## Fixes - -* **[Campaign]** Fixed liveries for premade squadrons all being off-by-one. -* **[UI]** Fixed numbering of waypoints in the map and flight dialog (first waypoint is now 0 rather than 1). - -# 8.0.0 - -Saves from 7.x are not compatible with 8.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.8.6.41066, including the new Sinai map. -* **[UI]** Limited size of overfull airbase display and added scrollbar. -* **[UI]** Waypoint altitudes can be edited in Waypoints tab of Edit Flight window. -* **[UI]** Moved air wing and transfer menus to the toolbar to improve UI fit on low resolution displays. -* **[UI]** Added basic game over dialog. - -## Fixes - -* **[Campaign]** Fix bug introduced in 7.0 where map strike target deaths are no longer tracked. -* **[Mission Generation]** Fix crash during mission generation caused by out of date DCS data for the Gazelle. -* **[Mission Generation]** Fix crash during mission generation when DCS beacon data is inconsistent. - -# 7.1.0 - -Saves from 7.0.0 are compatible with 7.1.0 - -## Features/Improvements - -* **[Engine]** Support for Normandy 2 airfields. -* **[Factions]** Replaced Patriot STRs "EWRs" with AN/FPS-117 for blue factions 1980 or newer. -* **[Mission Generation]** Added option to prevent scud and V2 sites from firing at the start of the mission. -* **[Mission Generation]** Added settings for controlling number of tactical commander, observer, JTAC, and game master slots. -* **[Mission Planning]** Per-flight TOT offsets can now be set in the flight details UI. This allows individual flights to be scheduled ahead of or behind the rest of the package. -* **[New Game Wizard]** The air wing configuration dialog will check for and reject overfull airbases before continuing when the new squadron rules are used. -* **[New Game Wizard]** Closing the air wing configuration dialog will now cancel and return to the new game wizard rather than reverting changes and continuing. -* **[New Game Wizard]** A warning will be displayed next to the new squadron rules button if the campaign predates the new rules and will likely require user intervention before continuing. -* **[UI]** Parking capacity of each squadron's base is now shown during air wing configuration to avoid overcrowding bases when beginning the game with full squadrons. - -## Fixes - -* **[Mission Planning]** BAI is once again plannable against missile sites and coastal defense batteries. -* **[UI]** Fixed formatting of departure time in flight details dialog. - -# 7.0.0 - -Saves from 6.x are not compatible with 7.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.8.5.40170. -* **[Engine]** Saved games are now a zip file of save assets for easier bug reporting. The new extension is .liberation.zip. Drag and drop that file into bug reports. -* **[Campaign]** Added options to limit squadron sizes and to begin all squadrons at maximum strength. Maximum squadron size is defined during air wing configuration with default values provided by the campaign. -* **[Campaign]** Added handling for more DCS death events. This probably does not catch any deaths that weren't previously tracked, but it should record them sooner, which will improve results for game crashes or other early exits. -* **[Campaign AI]** The campaign AI now prefers fulfilling missions with squadrons which have a matching primary task. Previously distance from target held a stronger influence than task preference. Primary tasks for squadrons are set by campaign designers but are user-configurable. -* **[Flight Planning]** Package TOT and composition can be modified after advancing time in Liberation. -* **[Mission Generation]** Units on the front line are now hidden on MFDs. -* **[Mission Generation]** Preset radio channels will now be configured for both A-10C modules. -* **[Mission Generation]** The A-10C II now uses separate radios for inter- and intra-flight comms (similar to other modern aircraft). -* **[Mission Generation]** Wind speeds no longer follow a uniform distribution. Median wind speeds are now much lower and the standard deviation has been reduced considerably at altitude but increased somewhat at MSL. -* **[Mission Generation]** Improved task generation for SEAD flights carrying TALDs. -* **[Mission Generation]** Added task timeout for SEAD flights with TALDs to prevent AI from overflying the target. -* **[Mission Generation]** Game state will automatically be checkpointed before fast-forwarding the mission, and restored on mission abort. This means that it's now possible to abort a mission and make changes without needing to manually re-load your game. -* **[Modding]** Updated Community A-4E-C mod version support to 2.1.0 release. -* **[Modding]** Add support for VSN F-4B and F-4C mod. -* **[Modding]** Added support for AI C-47 mod. -* **[Modding]** Custom factions can now be defined in YAML as well as JSON. JSON support may be removed in the future if having both formats causes confusion. -* **[Modding]** Campaigns which require custom factions can now define those factions directly in the campaign YAML. See Operation Aliied Sword for an example. -* **[Modding]** The `mission_types` field in squadron files has been removed. Squadron task capability is now determined by airframe, and the auto-assignable list has always been overridden by the campaign settings. -* **[Modding]** Aircraft task capabilities and preferred aircraft for each task are now moddable in the aircraft unit yaml files. Each aircraft has a weight per task. Higher weights are given higher preference. -* **[Modding]** Wind speed generation inputs are now moddable. See https://dcs-liberation.rtfd.io/en/latest/modding/weather.html. -* **[New Game Wizard]** Choices for some options will be remembered for the next new game. Not all settings will be preserved, as many are campaign dependent. -* **[New Game Wizard]** Lua plugins can now be set while creating a new game. -* **[New Game Wizard]** Squadrons can be directly replaced with a preset during air wing configuration rather than needing to remove and create a new squadron. -* **[New Game Wizard]** Squadron liveries can now be selected during air wing configuration. -* **[Squadrons]** Squadron-specific mission capability lists no longer restrict players from assigning missions outside the squadron's preferences. -* **[UI]** The orientation of objects like SAMs, EWRs, garrisons, and ships can now be manually adjusted. - -## Fixes - -* **[Campaign]** Fixed a longstanding bug where oversized airlifts could corrupt a save with empty convoys. -* **[Campaign]** Aircraft with built-in TGPs but without an external pod will no longer degrade automatic loadouts to iron bombs. -* **[Engine]** Fixed crash in startup caused by a corrupted Liberation preferences file. -* **[Flight Planning]** AEW&C missions are now plannable over FOBs and LHAs. -* **[Flight Planning]** BAI is no longer plannable against buildings. -* **[Modding]** Fixed an issue where Falklands campaigns created or edited with new versions of DCS could not be loaded. -* **[Modding]** Fixed decoding of campaign yaml files to use UTF-8 rather than the system locale's default. It's now possible to use "Bf 109 K-4 Kurfürst" as a preferred aircraft type. -* **[Mission Generation]** Planes will no longer spawn in helipads that are not also designated for fixed wing parking. -* **[Mission Generation]** Potentially an issue where ground war planning game state could become corrupted, preventing mission generation. -* **[Mission Generation]** Refueling tasks will now only be created for flights that have a tanker in their package. -* **[Mission Generation]** Fixed missing Tanker task on recovery tanker missions. -* **[UI]** Fixed error when resetting air wing configuration during game setup. -* **[UI]** Fixed flight plan recreation when changing mission type with "Recreate as" flight options. -* **[UI]** Fixed failure to launch UI when Liberation persistent preferences file was corrupt. - -# 6.1.1 - -## Fixes - -* **[Data]** Fixed unit ID for the KS-19 AAA. KS-19 would not previously generate correctly in missions. A new game is required for this fix to take effect. -* **[Flight Planning]** Automatic flight planning will no longer accidentally plan a recovery tanker instead of a theater refueling package. This fixes a potential crash during mission generation when opfor plans a refueling task at a sunk carrier. You'll need to skip the current turn to force opfor to replan their flights to get the fix. -* **[Mission Generation]** Using heliports (airports without any runways) will no longer cause mission generation to fail. -* **[Mission Generation]** Prevent helicopters from spawning into collisions at FARPs when more than one flight uses the same FARP. - -# 6.1.0 - -Saves from 6.0.0 are compatible with 6.1.0 - -## Features/Improvements - -* **[Engine]** Support for DCS 2.8.1.34437, including Blackshark 3. -* **[Factions]** Defaulted bluefor modern to use Georgian and Ukrainian liveries for Russian aircraft. -* **[Factions]** Added Peru. -* **[Flight Planning]** AEW&C and Refueling flights are now plannable on LHA carriers. -* **[Flight Planning]** Refueling flights planned on aircraft carriers will act as a recovery tanker for the carrier. -* **[Loadouts]** Adjusted F-15E loadouts. -* **[Mission Generation]** The previous turn will now be saved as last_turn.liberation when submitting mission results. This is often essential for debugging bug reports. **Include this file in the bug report whenever it is available.** -* **[Modding]** Added support for the HMS Ariadne, Achilles, and Castle class. -* **[Modding]** Added HMS Invincible to the game data as a helicopter carrier. - -## Fixes - -* **[Flight Planning]** Fixes CAS flights not having landing waypoints. -* **[Mission Generation]** Airbase and FOB capture is no longer blocked by grounded aircraft / helicopters. -* **[Squadrons]** Fixed the livery for the VF-33 F-14A squadron. -* **[Theaters]** Fixed Channel campaigns not having data for land/sea/obstacle boundaries, causing front lines to extend into forests and water. Requires a new campaign to get the fix. -* **[UI]** Fixed an issue where manual submit of mission results did not end the mission correctly. - -# 6.0.0 - -Saves from 5.x are not compatible with 6.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.8.0.33006. -* **[Factions]** Updated the Faction file structure. Older custom faction files will not work correctly and have to be updated to the new structure. -* **[Flight Planning]** Added preset formations for different flight types at hold, join, ingress, and split waypoints. Air to Air flights will tend toward line-abreast and spread-four formations. Air to ground flights will tend towards trail formation. -* **[Flight Planning]** Added the ability to plan tankers for recovery on package flights. This mission type will not be planned automatically. -* **[Flight Planning]** Air to Ground flights now have ECM enabled on lock at the join point, and SEAD/DEAD also have ECM enabled on detection and lock at ingress. -* **[Flight Planning]** AWACS flightplan changed from orbit to a racetrack to reduce data link disconnects which were caused by blind spots as a result of the bank angle. -* **[Flight Planning]** Added a new helo mission type: AirAssault which can be used to load and transport infantry troops from a pickup zone or a carrier to an enemy CP to capture it. -* **[Flight Planning]** Improved the Airlift mission type so that it now can be enforced within the unit transfer dialog and implemented CTLD support. This allows user to spawn sling loadable crates at the pickup location and fly transport flights. -* **[Mission Generation]** Added an option to fast-forward mission generation until the point of first contact (WIP). -* **[Mission Generation]** Added performance option to not cull IADS when culling would affect how mission is played at target area. -* **[Mission Generation]** Reworked the ground object generation which now uses a new layout system -* **[Mission Generation]** Added information about the modulation (AM/FM) of the assigned frequencies to the kneeboard and assign AM modulation instead of FM for JTAC. -* **[Mission Generation]** Added ice halos. -* **[Mission Generation]** Adjusted wind speeds. Wind speeds at high altitude are generally higher now. -* **[Mission Generation]** Added turbulence. Higher in Summer and Winter, also higher at day time than at nighttime. -* **[Modding]** Updated UH-60L mod version support to 1.3.1 -* **[Modding]** Updated the High Digit SAMs implementation and added the HQ-2 as well as the upgraded SA-2 and SA-3 Launchers from the mod. Threat range circles will now also be displayed correctly. -* **[Modding]** Theater information such as climate properties is now moddable. -* **[Modding]** Allow campaign designers to define default values for the economy settings (starting budget and multiplier). -* **[Modding]** Campaigns can now optionally define their start time by including a time in the `recommended_start_date` field. There is not currently a way to override the start time in the UI. -* **[Plugins]** Allow full support of the SkynetIADS plugin with all advanced features (connection nodes, power sources, command centers) if campaign supports it. -* **[Plugins]** Added support for the CTLD script by ciribob with many possible customization options and updated the JTAC Autolase to the CTLD included script. -* **[UI]** Added options to the loadout editor for setting properties such as HMD choice. -* **[UI]** Added separate images for the different carrier types. -* **[UI]** Add Accept/Reset buttons to Air Wing Configurator screen. - -## Fixes - -* **[Engine]** Fixed issue that prevented some weapon types like torpedoes from being recognized. -* **[Flight Planning]** Fixed a miscalculation of waypoint TOTs that would require time travel. -* **[Loadouts]** Improved the range of the F-16 CAS loadout by adding bags. -* **[Mission Generation]** AAA ground units now spawn correctly at the frontline -* **[Mission Generation]** Fixed SA-13 incorrectly created as SA-8 Loading Unit which will not be spawned in the generated mission. -* **[Mission Generation]** Fixed adding additional mission types for a squadron causing error messages when the mission type is not supported by the aircraft type by default -* **[Mission Generation]** Fixed an issue where SEAD/DEAD/BAI flights fired all missiles / bombs against a single unit in a group instead of targeting the whole group. -* **[Mission Generation]** Fixed an issue which generated the helipads at FARPs incorrectly and placed the helicopters within each other. -* **[Mission Generation]** Fixed an issue with SEAD missions flown by the AI when using the Skynet Plugin and anti-radiation missiles (ARM). The AI now correctly engages the SAM when it comes alive instead of diving into it. -* **[Mission Generation]** Fixed generation issue that would cause AI helicopters to get stuck after taking off from a FARP. -* **[Mission Generation]** Fixed mission scripting error caused by control points with apostrophes in their names, such as Tha'lah. -* **[Modding]** Campaigns that used quad zones for scenery targets will no longer load. Only circular zones were ever supported, but an implementation quirk allowed them to load in a way that would misbehave. A "No white triggerzones found" message during campaign generation is the sign of a broken campaign. -* **[Modding]** Loadouts with invalid weapons (typically new DCS weapons not yet available in Liberation) will be ignored rather than causing an error. -* **[Squadrons]** Fixed issue in air wing configuration that would allow squadrons to be created with no home base if no base was available. -* **[Squadrons]** Helicopter squadrons can no longer be assigned to FOBs that are not FARPs. -* **[UI]** Add vanilla theme weather and time of day icons -* **[UI]** Disable player slots for non-flyable aircraft. -* **[UI]** Fixed and issue where the liberation main exe was still running after application close. - -# 5.2.1 - -## Fixes - -* **[Mission Generation]** Work around DCS 2.8 bug preventing the AI from leaving their hold point. - -# 5.2.0 - -Saves from 5.1.0 are compatible with 5.2.0 - -## Features/Improvements - -* **[Engine]** Support for DCS 2.7.11.21408, including the new Apache AH-64D and the Syria map extension -* **[Mission Generation]** Improved FARP Helipad handling and creation (now includes windsocks) -* **[Modding]** Add UH-60L mod support -* **[Modding]** Updated Community A-4E-C mod version support to 2.0.0 release. Version 1.4.2 is no longer compatible, unless the mod default loadouts are deleted/modified. -* **[Modding]** Updated JAS-39-C mod support for v1.8.0-beta -* **[Campaign]** Peace Spring, Vectron's Claw, Vegas Nerve, Scenic Route 2 campaign update -* **[Campaign]** Added Tripoint Hostility campaign by Fuzzle -* **[Campaign]** Add 3 new campaigns from Sith1144 - -## Fixes - -* **[Mission Generation]** Fixed incorrect SA-5 and NASAMS threat range when TR destroyed. It will not count as threat anymore when the TR is dead. -* **[Mission Generation]** Fixed "Max Threat Range" error -* **[Mission Generation]** Fix unculled zones not updating when needed -* **[Mission Planner]** Now allows squadron transfers to control points where the number of free slots matches exactly the expected size of the transferring squadron next turn. -* **[Data]** Removed Fw 190 A-8 and D-9 from Germany 1940 and 1942 faction list for historical accuracy. -* **[Data]** Updated Loadouts for Tornado GR4, F-15E and F-16C -* **[Data]** Corrected some unit data -* **[UI]** Fixed various UI issues (for example Scaling and HighDPI) -* **[UI]** Typhoon GR4 and IDS images - -# 5.1.0 - -Saves from 5.0.0 are compatible with 5.1.0 - -## Features/Improvements - -* **[Engine]** Support for DCS 2.7.9.17830 and newer, including the HTS and ECM pod. -* **[Campaign]** Add option to manually add and remove squadrons and different aircraft type in the new game wizard / air wing configuration dialog. -* **[Mission Generation]** Add Option to enforce the Easy Communication setting for the mission -* **[Mission Generation]** Add Option to select between only night missions, day missions or any time (default). -* **[Modding]** Add F-104 mod support - -## Fixes - -* **[Campaign]** Fixed some minor issues in campaigns which generated error messages in the log. -* **[Campaign]** Changed the way how map object / scenery kills where tracked. This fixes issues with kill recognition after map updates from ED which change the object ids and therefore prevent correct kill recognition. -* **[Mission Generation]** Fixed incorrect radio specification for the AN/ARC-222. -* **[Mission Generation]** Fixed mission scripting error when using a dedicated server. -* **[Mission Generation]** Fixed an issue where empty convoys lead to an index error when a point capture made a pending transfer of units not completable anymore. -* **[Mission Generation]** Corrected Viggen FR22 & FR24 preset channels for the DCS 2.7.9 update -* **[Mission Generation]** Fixed the SA-5 Generator to use the P-19 FlatFace SR as a Fallback radar if the faction does not have access to the TinShield SR. -* **[UI]** Enable / Disable the settings, save and stats actions if no game is loaded to prevent an error as these functions can only be used on a valid game. -* **[UI]** Added missing icons for Tornado GR4, and Tornado IDS. - -# 5.0.0 - -Saves from 4.x are not compatible with 5.0. - -## Features/Improvements - -* **[Campaign]** Weather! Theaters now experience weather that is more realistic for the region and its current season. For example, Persian Gulf will have very hot, sunny summers and Marianas will experience lots of rain during fall. These changes affect pressure, temperature, clouds and precipitation. Additionally, temperature will drop during the night, by an amount that is somewhat realistic for the region. -* **[Campaign]** Weapon data such as fallbacks and introduction years is now moddable. Due to the new architecture to support this, the old data was not automatically migrated. -* **[Campaign]** Era-restricted loadouts will now skip LGBs when no TGP is available in the loadout. This only applies to default loadouts; buddy-lasing can be coordinated with custom loadouts. -* **[Campaign]** FOBs control point can have FARP/helipad slot and host helicopters. To enable this feature on a FOB, add "Invisible FARP" statics objects near the FOB location in the campaign definition file. -* **[Campaign]** Squadrons now have a home base and will not operate out of other bases. See https://github.com/dcs-liberation/dcs_liberation/issues/1145 for status. -* **[Campaign]** Aircraft now belong to squadrons rather than bases to support squadron location transfers. -* **[Campaign]** Skipped turns are no longer counted as defeats on front lines. -* **[Campaign AI]** Overhauled campaign AI target prioritization. -* **[Campaign AI]** Player front line stances can now be automated. Improved stance selection for AI. -* **[Campaign AI]** Reworked layout of hold, join, split, and ingress points. Should result in much shorter flight plans in general while still maintaining safe join/split/hold points. -* **[Campaign AI]** Auto-planning mission range limits are now specified per-aircraft. On average this means that longer range missions will now be plannable. The limit only accounts for the direct distance to the target, not the path taken. -* **[Campaign AI]** Transport aircraft will now be bought only if necessary at control points which can produce ground units and are capable to operate transport aircraft. -* **[Campaign AI]** Aircraft will now only be automatically purchased or assigned at appropriate bases. Naval aircraft will default to only operating from carriers, Harriers will default to LHAs and shore bases, helicopters will operate from anywhere. This can be customized per-squadron. -* **[Engine]** Support for DCS 2.7.7.14727 and newer, including support for F-16 CBU-105s, SA-5s, and the Forrestal. -* **[Kneeboard]** Minimum required fuel estimates have been added to the kneeboard for aircraft with supporting data (currently only the Hornet and Viper). -* **[Kneeboard]** QNH (pressure MSL) and temperature have been added to the kneeboard. -* **[Mission Generation]** EWRs are now also headed towards the center of the conflict -* **[Mission Generation]** FACs can now use FC3 compatible laser codes. Note that this setting is global, not per FAC. -* **[Modding]** Can now install custom campaigns to /Liberation/Campaigns instead of the Liberation install directory. -* **[Modding]** Campaigns can now define a default start date. -* **[Modding]** Campaigns now specify the squadrons that are present in the campaign, their roles, and their starting bases. Players can customize this at game start but the campaign will choose the defaults. -* **[New Game Wizard]** Can now customize the player's air wing before campaign start to disable, relocate, or rename squadrons. -* **[Plugins]** Updated SkynetIADS to 2.4.0 (adds SA-5 support). -* **[UI]** Sell Button for aircraft will be disabled if there are no units available to be sold or all are already assigned to a mission -* **[UI]** Enemy aircraft inventory now viewable in the air wing menu. - -## Fixes - -* **[Campaign]** Naval control points will no longer claim ground objectives during campaign generation and prevent them from spawning. -* **[Campaign]** Units aboard sunk cargo ships will now have their losses tracked properly. -* **[Mission Generation]** Mission results and other files will now be opened with enforced utf-8 encoding to prevent an issue where destroyed ground units were untracked because of special characters in their names. -* **[Mission Generation]** Fixed generation of landing waypoints so that the AI obeys them. -* **[Mission Generation]** AI carrier aircraft with a start time of T+0 will now start at T+1s to avoid traffic jams. -* **[Mission Generation]** Fixed cases of unused aircraft not being spawned at airfields as soon as any airport filled up. -* **[Mission Generation]** Fixed cases with multiple client flights of the same airframe all received the same preset channels. -* **[Mission Generation]** F-14A is now generated with stored alignment. -* **[Mission Generation]** Su-33s set to cold or warm start on the Kuznetsov will always be generated as runway starts to avoid the AI getting stuck. -* **[Mission Generation]** Fixed AI not receiving anti-ship tasks against carriers and LHAs. -* **[Mods]** Fixed broken A-4 support causing no weapons to be available. -* **[UI]** Selling of Units is now visible again in the UI dialog and shows the correct amount of sold units -* **[UI]** Fixed bug where an incompatible campaign could be generated if no action is taken on the campaign selection screen. - -# 4.1.1 - -Saves from 4.1.0 are compatible with 4.1.1. - -## Fixes - -* **[Campaign]** Fixed broken support for Mariana Islands map. -* **[Mission Generation]** Fix SAM sites pointing towards the center of the conflict. -* **[Flight Planning]** No longer using Su-34 for CAP missions. - -# 4.1.0 - -Saves from 4.0.0 are compatible with 4.1.0. - -## Features/Improvements - -* **[Campaign]** Air defense sites now generate a fixed number of launchers per type. -* **[Campaign]** Added support for Mariana Islands map. -* **[Campaign AI]** Adjustments to aircraft selection priorities for most mission types. -* **[Engine]** Support for DCS 2.7.4.9632 and newer, including the Marianas map, F-16 JSOWs, NASAMS, and Tin Shield EWR. -* **[Flight Planning]** CAP patrol altitudes are now set per-aircraft. By default the altitude will be set based on the aircraft's maximum speed. -* **[Flight Planning]** CAP patrol speeds are now set per-aircraft to be more suitable/sensible. By default the speed will be set based on the aircraft's maximum speed. -* **[Mission Generation]** Improvements for better support of the Skynet Plugin and long range SAMs are now acting as EWR -* **[Mission Generation]** SAM sites are now headed towards the center of the conflict -* **[Mods]** Support for latest version of Gripen mod. In-progress campaigns may need to re-plan Gripen flights to pick up updated loadouts. -* **[Plugins]** Increased time JTAC Autolase messages stay visible on the UI. -* **[Plugins]** Updated SkynetIADS to 2.2.0 (adds NASAMS support). -* **[UI]** Added ability to take notes and have those notes appear as a kneeboard page. -* **[UI]** Hovering over the weather information now dispalys the cloud base (meters and feet). -* **[UI]** Google search link added to unit information when there is no information provided. -* **[UI]** Control point name displayed with ground object group name on map. -* **[UI]** Buy or Replace will now show the correct price for generated ground objects like sams. -* **[UI]** Improved logging for frontline movement to be more descriptive about what happened and why. -* **[UI]** Brought ruler map module into source, which should fix file integrity issues with the module. - -## Fixes - -* **[Campaign]** Fixed the Silkworm generator to include launchers and not all radars. -* **[Data]** Fixed Introduction dates for targeting pods (ATFLIR and LITENING were both a few years too early). -* **[Data]** Removed SA-10 from Syria 2011 faction. -* **[Economy]** EWRs can now be bought and sold for the correct price and can no longer be used to generate money -* **[Flight Planning]** Helicopters are now correctly identified, and will fly ingress/CAS/BAI/egress and similar at low altitude. -* **[Flight Planning]** Fixed potential issue with angles > 360° or < 0° being generated when summing two angles. -* **[Mission Generation]** The lua data for other plugins is now generated correctly -* **[Mission Generation]** Fixed problem with opfor planning missions against sold ground objects like SAMs -* **[Mission Generation]** The legacy always-available tanker option no longer prevents mission creation. -* **[Mission Generation]** Prevent the creation of a transfer order with 0 units for a rare situtation when a point was captured. -* **[Mission Generation]** Planned transfers which will be impossible after a base capture will no longer prevent the mission result submit. -* **[Mission Generation]** Fix occasional KeyError preventing mission generation when all units of the same type in a convoy were killed. -* **[Mission Generation]** Fix for AAA Flak generator using Opel Blitz preventing the mission from being generated because duplicate unit names were used. -* **[Mission Generation]** Fixed a potential bug with laser code generation where it would generate invalid codes. -* **[UI]** Statistics window tick marks are now always integers. -* **[UI]** Statistics window now shows the correct info for the turn -* **[UI]** Toggling custom loadout for an aircraft with no preset loadouts no longer breaks the flight. - -# 4.0.0 - -Saves from 3.x are not compatible with 4.0. - -## Features/Improvements - -* **[Engine]** Support for DCS 2.7.2.7910.1 and newer, including Cyprus, F-16 JDAMs, and the Hind. -* **[Campaign]** Squadrons now (optionally, off by default) have a maximum size and killed pilots replenish at a limited rate. -* **[Campaign]** Added an option to disable levelling up of AI pilots. -* **[Campaign]** Added Russian Intervention 2015 campaign on Syria, for a small and somewhat realistic Russian COIN scenario. -* **[Campaign]** Added Operation Atilla campaign on Syria, for a reasonably large invasion of Cyprus scenario. -* **[Campaign AI]** AI will plan Tanker flights. -* **[Campaign AI]** Removed max distance for AEW&C auto planning. -* **[Economy]** Adjusted prices for aircraft to balance out some price inconsistencies. -* **[Factions]** Added more tankers to factions. -* **[Flight Planner]** Added ability to plan Tankers. -* **[Modding]** Campaign format version is now 7.0 to account for DCS map changes that made scenery strike targets incompatible with existing campaigns. -* **[Mods]** Added support for the Gripen mod. -* **[Mods]** Removes MB-339PAN support, as the mod is now deprecated and no longer works with DCS 2.7+. -* **[Mission Generation]** Added support for "Neutral Dot" label options. -* **[New Game Wizard]** Mods are now selected via checkboxes in the new game wizard, not as separate factions. -* **[UI]** Ctrl click and shift click now buy or sell 5 or 10 units respectively. -* **[UI]** Multiple waypoints can now be deleted simultaneously if multiple waypoints are selected. -* **[UI]** Carriers and LHAs now match the colour of airfields, and their destination icons are translucent. -* **[UI]** Updated intel box text for first turn. -* **[UI]** Base Capture Cheat is now usable at all bases and can also be used to transfer player-owned bases to OPFOR. -* **[UI]** Pass Turn button is relabled as "Begin Campaign" on Turn 0. -* **[UI]** Added a ruler to the map. -* **[UI]** Liberation now saves games to `/Liberation/Saves` by default to declutter the main directory. - -## Fixes - -* **[Campaign AI]** Fix procurement for factions that lack some unit types. -* **[Campaign AI]** Fix auto purchase of aircraft for factions that have no transport aircraft. -* **[Campaign AI]** Fix refunding of pending aircraft purchases when a side has no factory available. -* **[Mission Generation]** Fixed problem with mission load when control point name contained an apostrophe. -* **[Mission Generation]** Fixed EWR group names so they contribute to Skynet again. -* **[Mission Generation]** Fixed duplicate name error when generating convoys and cargo ships when creating manual transfers after loading a game. -* **[Mission Generation]** Fixed empty convoys not being disbanded when all units are killed/removed. -* **[Mission Generation]** Fixed player losing frontline progress when skipping from turn 0 to turn 1. -* **[Mission Generation]** Fixed issue where frontline would only search to the right for valid locations. -* **[UI]** Made non-interactive map elements less obstructive. -* **[UI]** Added support for Neutral Dot difficulty label -* **[UI]** Clear skies at night no longer described as "Sunny" by the weather widget. -* **[UI]** Removed ability to buy (useless) ground units at carriers and LHAs. -* **[UI]** Fixed enable/disable of buy/sell buttons. -* **[UI]** EWRs now appear in the custom waypoint list. - -# 3.0.0 - -Saves from 2.5 are not compatible with 3.0. - -## Features/Improvements - -* **[Campaign]** Ground units can now be transferred by road, airlift, and cargo ship. See https://github.com/dcs-liberation/dcs_liberation/wiki/Unit-Transfers for more information. -* **[Campaign]** Ground units can no longer be sold. To move units to a new location, transfer them. -* **[Campaign]** Ground units must now be recruited at a base with a factory and transferred to their destination. When buying units in the UI, the purchase will automatically be fulfilled at the closest factory, and a transfer will be created on the next turn. -* **[Campaign]** Non-control point FOBs will no longer spawn. -* **[Campaign]** Added squadrons and pilots. See https://github.com/dcs-liberation/dcs_liberation/wiki/Squadrons-and-pilots for more information. -* **[Campaign]** Capturing a base now depopulates all of its attached objectives with units: air defenses, EWRs, ships, armor groups, etc. Buildings are captured. -* **[Campaign]** Ammunition Depots determine how many ground units can be deployed on the frontline by a control point. -* **[Campaign AI]** AI now considers Ju-88s for CAS, strike, and DEAD missions. -* **[Campaign AI]** AI planned AEW&C missions will now be scheduled ASAP. -* **[Campaign AI]** AI now considers the range to the SAM's threat zone rather than the range to the SAM itself when determining target priorities. -* **[Campaign AI]** Auto purchase of ground units will now maintain unit composition instead of buying randomly. The unit composition is predefined. -* **[Campaign AI]** Auto purchase will aim to purchase enough ground units to support the frontline, plus 30% reserve units. -* **[Campaign AI]** Auto purchase will now adjust its air/ground balance to favor whichever is under-funded. -* **[Flight Planner]** Desired mission length is now configurable (defaults to 60 minutes). A BARCAP will be planned every 30 minutes. Other packages will simply have their takeoffs spread out or compressed such that the last flight will take off around the mission end time. -* **[Flight Planner]** Flight plans now include bullseye waypoints. -* **[Flight Planner]** Differentiated SEAD and SEAD escort. SEAD is tasked with suppressing the package target, SEAD escort is tasked with protecting the package from all SAMs along its route. -* **[Flight Planner]** Planned airspeed increased to 0.85 mach for supersonic airframes and 85% of max speed for subsonic. -* **[Flight Planner]** Taxi time estimation for airfields increased from 5 minutes to 8 minutes. -* **[Flight Planner]** Reduce expected error margin for flight plans from 10% to 5%. -* **[Flight Planner]** SEAD flights are scheduled one minute ahead of the package's TOT so that they can suppress the site ahead of the strike. -* **[Flight Planner]** Automatic ATO generation for the player's coalition can now be disabled in the settings. -* **[Payloads]** AI flights for most air to ground mission types (CAS excluded) will have their guns emptied to prevent strafing fully armed and operational battle stations. Gun-reliant airframes like A-10s and warbirds will keep their bullets. -* **[Kneeboard]** ATC table overflow alleviated by wrapping long airfield names and splitting ATC frequency and channel into separate rows. -* **[UI]** Overhauled the map implementation. Now uses satellite imagery instead of low res map images. Display options have moved from the toolbar to panels in the map. -* **[UI]** Campaigns generated for an older or newer version of the game will now be marked as incompatible. They can still be played, but bugs may be present. -* **[UI]** DCS loadouts are now selectable in the loadout setup menu. -* **[UI]** Added global aircraft inventory view under Air Wing dialog. -* **[UI]** Base menu now shows information about ground unit deployment limits. -* **[Modding]** Campaigns now choose locations for factories to spawn. -* **[Modding]** Campaigns now choose locations for ammunition depots to spawn. -* **[Modding]** Campaigns now use map structures as strike targets. -* **[Modding]** Campaigns may now set *any* objective type to be a required spawn rather than random chance. Support for random objective generation was removed. -* **[Modding]** Campaigns may now place AAA objectives. -* **[Modding]** Can now install custom factions to /Liberation/Factions instead of the Liberation install directory. -* **[Performance Settings]** Added a settings to lower the number of smoke effects generated on frontlines. Lowered default settings for frontline smoke generators, so less smoke should be generated by default. -* **[Configuration]** Liberation preferences (DCS install and save game location) are now saved to `%LOCALAPPDATA%/DCSLiberation` to prevent needing to reconfigure each new install. -* **[Skynet]** Updated to 2.1.0. - -## Fixes - -* **[Campaign AI]** Fix purchase of aircraft by priority (the faction's list was being used as the priority list rather than the game's). -* **[Campaign AI]** Fixed bug causing AI to over-purchase cheap aircraft. -* **[Campaign AI]** Auto planner will no longer attempt to plan missions for which the faction has no compatible aircraft. -* **[Campaign AI]** Stop purchasing aircraft after the first unaffordable package to attempt to complete more packages rather than filling airfields with cheap escorts that will never be used. -* **[Campaign]** Fixed bug where offshore strike locations were being used to spawn ship objectives. -* **[Campaign]** EWR sites are now purchasable. -* **[Flight Planner]** AI strike flight plans now include the correct target actions for building groups. -* **[Flight Planner]** AI BAI/DEAD/SEAD flights now have tasks to attack all groups at the target location, not just the primary group (for multi-group SAM sites). -* **[Flight Planner]** Fixed some contexts where damaged runways would be used. Destroying a carrier will no longer break the game. - -# 2.5.1 - -## Features/Improvements - -* **[UI]** Engagement ranges are now displayed by default. -* **[UI]** Engagement range display generalized to work for all patrolling flight plans (BARCAP, TARCAP, and CAS). -* **[Flight Planner]** Front lines no longer project threat zones to avoid pushing BARCAPs back so much. TARCAPs will be forcibly planned but strike packages will not route around front lines even if it is reasonable to do so. - -## Fixes - -* **[Campaigns]** EWRs associated with a base will now only be generated near the base. -* **[Flight Planner]** Fixed error when generating AEW&C flight plans in campaigns with no front lines. - -# 2.5.0 - -Saves from 2.4 are not compatible with 2.5. - -## Features/Improvements - -* **[Engine]** DCS 2.7 Support -* **[UI]** Improved FOB menu, added a custom banner, and do not display aircraft recruitment menu -* **[Flight Planner]** Added AEW&C missions. (by siKruger) -* **[Kneeboard]** Added dark kneeboard option (by GvonH) -* **[Campaigns]** Multiple EWR sites may now be generated, and EWR sites may be generated outside bases (by SnappyComebacks) -* **[Mission Generation]** Cloudy and rainy (but not thunderstorm) weather will use the cloud presets from DCS 2.7. -* **[Plugins]** Added LotATC export plugin (by drsoran) -* **[Plugins]** Added Splash Damage Plugin (by Wheelijoe) -* **[Loadouts]** Replaced Litening with ATFLIR for all default F/A-18C loadouts. - -## Fixes - -* **[Flight Planner]** Front lines now project threat zones, so TARCAP/escorts will not be pruned for flights near the front. Packages may also route around the front line when practical. -* **[Flight Planner]** Fixed error when planning BAI at SAMs with dead subgroups. -* **[Flight Planner]** Mig-19 was not allowed for CAS roles fixed -* **[Flight Planner]** Increased size of navigation planning area to avoid plannign failures with distant waypoints. -* **[Flight Planner]** Fixed UI refresh when unchecking the "default loadout" box in the loadout editor. -* **[Objective names]** Fixed typos in objective name : ARMADILLLO -> ARMADILLO (by SnappyComebacks) -* **[Payloads]** F-86 Sabre was missing a custom payload -* **[Payloads]** Added GAR-8 period restrictions (by Mustang-25) -* **[Campaign]** Date now progresses. -* **[Campaign]** Added game over message when a coalition runs out of functioning airbases. -* **[Mission Generation]** Fixed "invalid face handle" error in kneeboard generation that occurred on some machines. - -## Regressions - -* **[Mod Support]** Stopped support for 2.5.5 Rafale Mode, and removed factions that were using it -* **[Mod Support]** Su-57 mod support might be out of date - -# 2.4.3 - -## Features/Improvements - -* **[New Game Wizard]** Added the possibility to setup custom start date - -## Fixes - -* **[Mods]** Updated C-130J mod data to version 6.4 -* **[Mods]** Updated F-22A mod to latest version - -# 2.4.2 - -## Features/Improvements - -* **[Factions]** Introduction dates and fallback weapons added for US, Russian, UK, and French weapons. Huge thanks to @TheCandianVendingMachine for the massive amount of data entry! -* **[Campaigns]** Added 1995 start dates. - -## Fixes - -* **[Economy]** Pending ground unit purchases will also be transferred when a connected base is captured. -* **[UI]** Fixed rounding of budget in recruitment menu. - -# 2.4.1 - -## Fixes - -* **[Units]** Fixed syntax error with the SH-60B payload file. -* **[Culling]** Missile sites generate reasonably sized non-cull zones rather than 100km ones. -* **[UI]** Budget display is also now rounded to 2 decimal places. -* **[UI]** Fixed some areas where the old, non-pretty name was displayed to users. - -# 2.4.0 - -Saves from 2.3 are not compatible with 2.4. - -## Highlights - -* Improved flight plan generation to avoid loitering in or traveling through threatened areas when practical. -* Improved AI aircraft purchasing behavior. -* Era-restricted weapons (work in progress). -* Tons of UI polish. -* Rebalanced economy to keep opfor competitive over the course of the game. - -## Features/Improvements - -* **[Flight Planner]** Air-to-air and SEAD escorts will no longer be automatically planned for packages that are not in range of threats. -* **[Flight Planner]** Non-custom flight plans will now navigate around threat areas en route to the target area when practical. -* **[Flight Planner]** Flight plans along front lines now ensure that the race track start is closer to the departure airfield than the race track end. -* **[Campaign AI]** Auto-purchase now prefers airfields that are not within range of the enemy. -* **[Campaign AI]** Auto-purchase now prefers the best aircraft for the task, but will attempt to maintain some variety. -* **[Campaign AI]** Opfor now sells off odd aircraft since they're unlikely to be used. -* **[Campaign AI]** Multiple rounds of CAP will be planned (roughly 90 minutes of coverage). Default starting budget has increased to account for the increased need for aircraft. -* **[Mission Generator]** Multiple groups are created for complex SAM sites (SAMs with additional point defense or SHORADS), improving Skynet behavior. -* **[Mission Generator]** Default start type can now be chosen in the settings. This replaces the non-functional "AI Parking Start" option. **Selecting any type other than cold will break OCA/Aircraft missions.** -* **[Cheat Menu]** Added ability to toggle base capture and frontline advance/retreat cheats. -* **[Skynet]** Updated to 2.0.1. -* **[Skynet]** Point defenses are now configured to remain on to protect the site they accompany. -* **[Hercules]** Updated the Hercules Cargo list file. -* **[Balance]** Opfor now gains income using the same rules as the player, significantly increasing their income relative to the player for most campaigns. -* **[Balance]** Units now retreat from captured bases when able. Units with no retreat path will be captured and sold. -* **[Economy]** FOBs generate only $10M per turn (previously $20M like airbases). -* **[Economy]** Carriers and off-map spawns generate no income (previously $20M like airbases). -* **[Economy]** Sales of aircraft and ground vehicles can now be cancelled before the next turn begins. -* **[UI]** Multi-SAM objectives now show threat and detection rings per group. -* **[UI]** New icon for AA sites with no active threat. -* **[UI]** Unit names are now prettier and more accurate, and can now be set per-country for added historical flavour. -* **[UI]** Default loadout is now shown for flights with no custom loadout selected. -* **[UI]** Aircraft for a new flight are now only selectable if they match the task type for that flight. -* **[UI]** WIP - There is now a unit info button for each unit in the recruitment list, that should help newer players learn what each unit does. -* **[UI]** Docs for time-on-target and creating new theaters/factions/loadouts are now linked in the UI at the appropriate places. -* **[UI]** ASAP is now a checkbox rather than a button. Enabling this will disable the TOT selector but changes to the package structure will automatically re-ASAP the package. -* **[UI]** Arrival airfield is now shown in the flight list if it differs from the departure airfield. -* **[UI]** Start type can now be selected when creating a flight. -* **[UI]** Arrival and divert airfields can be edited after the flight is created. -* **[Factions]** Added option for date-based loadout restriction. Active radar homing missiles are handled, patches welcome for the other thousand weapons. -* **[Factions]** Added Poland 2010 faction. -* **[Factions]** Added Greece 2005 faction. -* **[Factions]** Added Iran 1988 faction. -* **[Units]** Support for E-2 Hawkeye, SH-60B Seahawk, S-3B Viking (thanks to awinterquest) and SpGH Dana - these are now being used by appropriate factions. -* **[Culling]** Missile sites are no longer culled. -* **[Campaigns]** Added campaign "Black Sea Lite" by Starfire -* **[Campaigns]** Added campaign "Exercise Vegas Nerve" by Starfire -* **[New game Wizard]** The theater page is now the first page of the campaign wizard, recommended factions will be selected automatically on the faction selection page -* **[New game Wizard]** Added information text about the selected campaign performance. -* **[Mod Support]** Added support for High Digit SAMs mod 1.4.0 -* **[Mod Support]** Added SAMs sites generator : KS19Generator, SA10BGenerator, SA12Generator, SA17Generator, SA20Generator, SA20BGenerator, SA23Generator - -## Fixes - -* **[Hercules]** Updated the default Hercules radio frequency. -* **[Economy]** Pending unit orders at captured bases will be refunded. -* **[UI]** Carrier group SAM threat rings now move with the carrier. -* **[UI]** Base intel menu no longer compresses text, and is now scrollable. -* **[UI]** Edit Flight window is now dynamically sized to adapt to the width of waypoint names, so they no longer get truncated. -* **[UI]** Budget income display is now rounded to 2 decimal places. -* **[UI]** Fixed incorrect income per turn displayed for strike target tooltip. -* **[Factions]** USA with C-130 faction now links to the required mod. -* **[Campaign]** Fixed issue where destroyed buildings would sometimes not count as destroyed and thus respawn. -* **[Campaign]** Fixed issue where destroyed runways were not registered. -* **[Units]** J-11A is no longer spawned with empty loadout. -* **[Units]** F-14B is no longer spawned with empty loadout for fighter sweep tasks. -* **[Units]** Pyotr Velikiy cruiser has been removed for now as it's nearly unkillable. -* **[Units]** Submarines have been removed for now as they aren't wholly functional. -* **[Units]** Fixed "FACTION ERROR : Unable to find OliverHazardPerryGroupGenerator in pydcs" error at startup. -* **[Mission Generator]** Fixed a bug where units set to Aggressive stance sometimes did not move. -* **[Mission Generator]** Flyover points for OCA/Aircraft missions are now generated correctly. -* **[Flight Planner]** Fixed not being able to create custom waypoints for buildings. -* **[Flight Planner]** Strike missions will no longer be automatically planned against SAMs. -* **[Flight Planner]** Strike missions will no longer be automatically planned against FOB structures. - -# 2.3.4 - -## Fixes: -[Mission Generator] Mission generator would crash when generating fire missions for destroyed SCUD sites - fixed - -# 2.3.3 - -## Features/Improvements -* **[Campaigns]** Reworked Golan Heights campaign on Syria, (Added FOB and preset locations for SAMS) -* **[Campaigns]** Added a lite version of the Golan Heights campaign -* **[Campaigns]** Reworked Syrian Civil War campaign (Added FOB and preset locations for SAMS) -* **[Campaigns]** Reworked Emirates campaign -* **[Campaigns]** AA units added to frontlines and updated all factions to include some frontline AA units. -* **[Mission Generator]** Infantry will only be generated for APC and IFV groups -* **[Mission Generator]** Infantry squads size is not randomized anymore -* **[Mission Generator]** Infantry squads can have a mortar. -* **[Mission Generator]** SCUD missiles sites will now fire on enemy controls points in range when possible -* **[Factions]** Updated Nato Desert Storm to include F-14A -* **[Factions]** Updated Iraq 1991 factions to include Zsu-57 and Mig-29A -* **[Factions]** Germany 1944, added Stug III and Stug IV -* **[Factions]** Added factions Insurgents (Hard) with better and more weapons -* **[Plugins]** [The EWRS plugin](https://github.com/Bob7heBuilder/EWRS) is now included. -* **[UI]** Added enemy intelligence summary and details window. - -## Fixes: -* **[Factions]** AI would never buy artillery units for the frontline - fixed -* **[Factions]** Removed the F-111 unit from the NATO desert storm faction. (Recruiting it would cause crashes in DCS, since it is not a valid unit) -* **[Campaign]** Automatic redeployment of ground units would sometimes fail - fixed -* **[Mission Generator]** Artillery groups would retreat in the wrong direction - fixed -* **[Units]** Fixed SPG_Stryker_M1128_MGS not being in db -* **[UI]** Fixed and added many missing ground units icons -* **[UI]** Ship groups could be replaced by SAM sites in the UI, which would lead to broken mission being generated - fixed -* **[New Game Wizard]** Removed the "mid game" campaign generator option which is currently broken -* **[Mission Generator]** Empty navy groups will no longer be generated -* **[Mission Generator]** Fixed BAI, SEAD, and DEAD flights ocassionally being assigned the wrong targets. -* **[Flight Planner]** Fixed not being able to plan packages against opfor carriers -* **[UI]** Repaired SAMs no longer show as dead. -* **[UI]** Fixed not being able to manage a disbanded site after disbanding and closing the base menu. - -# 2.3.2 - -## Features/Improvements -* **[Units]** Support for newly added BTR-82A, T-72B3 -* **[Units]** Added ZSU-57 AAA sites -* **[Culling]** BARCAP missions no longer create culling exclusion zones. -* **[Flight Planner]** Improved TOT planning. Negative start times no longer occur with TARCAPs and hold times no longer affect planning for flight plans without hold points. -* **[Factions]** Added Iraq 1991 faction (thanks again to Hawkmoon!) - -## Fixes: -* **[Mission Generator]** Fix mission generation error when there are too many radio frequency to setup for the Mig-21 -* **[Mission Generator]** Fix ground units not moving forward -* **[Mission Generator]** Fixed assigned radio channels overlapping with beacons. -* **[Flight Planner]** Fix creation of custom waypoints. -* **[Campaigns]** Fixed many cases of SAMs spawning on the runways/taxiways in Syria Full. - -# 2.3.1 - -## Features/Improvements -* **[UX]** Added a warning message when the player is attempting to buy more planes at an already full airbase. -* **[Campaigns]** Migrated Syria full map to new format. (Thanks to Hawkmoon) -* **[Faction]** Added NATO desert Storm faction (Thanks to Hawkmoon) - -## Fixes: -* **[AI]** CAP flights will engage enemies again. -* **[Campaigns]** Fixed a missing path on the Caucasus Full Map campaign - -# 2.3.0 - -## Features/Improvements -* **[Campaign Map]** Overhauled the campaign model -* **[Campaign Map]** Possible to add FOB as control points -* **[Campaign Map]** Added off-map spawn locations -* **[Campaign AI]** Overhauled AI recruiting behaviour -* **[Campaign AI]** Added AI procurement for Blue -* **[Campaign]** New Campaign: "Black Sea" -* **[Mission Planner]** Possible to move carrier and tarawa on the campaign map -* **[Mission Generator]** Infantry squads on frontline can have manpads -* **[Mission Generator]** Unused aircraft now spawned to allow for OCA strikes -* **[Mission Generator]** Opfor now obeys parking limits -* **[Mission Generator]** Support for Anubis C-130 Hercules mod -* **[Flight Planner]** Added fighter sweep missions. -* **[Flight Planner]** Added BAI missions. -* **[Flight Planner]** Added anti-ship missions. -* **[Flight Planner]** Differentiated BARCAP and TARCAP. TARCAP is now for hostile areas and will arrive before the package. -* **[Flight Planner]** Added OCA missions -* **[Flight Planner]** Added Alternate/divert airfields -* **[Culling]** Added possibility to include/exclude carriers from culling zones -* **[QOL]** On liberation startup, your latest save game is loaded automatically -* **[Units]** Reduced starting fuel load for C101 -* **[UI]** Inform the user of the weather -* **[UI]** Added toolbar buttons to change map display settings -* **[Game]** Added new Economy options for adjusting income multipliers and starting budgets. - -## Fixes : -* **[Map]** Missiles sites now have a proper icon and will not re-use the SAM sites icon -* **[Mission Generator]** Ground unit waypoints improperly set to "On Road" - fixed -* **[Mission Generator]** Target waypoints not at ground level - fixed -* **[Mission Generator]** Selected skill not applied to Helicopters - fixed -* **[Mission Generator]** Ground units do not always spawn - fixed -* **[Kneeboard]** Briefing waypoints off by one - fixed -* **[Game]** Destroyed buildings still granting budget - fixed - -# 2.2.1 - -## Features/Improvements -* **[Factions]** Added factions : Georgia 2008, USN 1985, France 2005 Frenchpack by HerrTom -* **[Factions]** Added map Persian Gulf full by Plob -* **[Flight Planner]** Player flights with start delays under ten minutes will spawn immediately. -* **[UI]** Mission start screen now informs players about delayed flights. -* **[Units]** Added support for F-14A-135-GR -* **[Modding]** Possible to setup liveries overrides in factions definition files - -## Fixes : -* **[Flight Planner]** Hold, join, and split points are planned cautiously near enemy airfields. Ascend/descend points are no longer planned. -* **[Flight Planner]** Custom waypoints are usable again. Not that in most cases custom flight plans will revert to the 2.1 flight planning behavior. -* **[Flight Planner]** Fixed UI bug that made it possible to create empty flights which would throw an error. -* **[Flight Planner]** Player flights from carriers will now be delayed correctly according to the player's settings. -* **[Misc]** Spitfire variant with clipped wings was not seen as flyable by DCS Liberation (hence could not be setup as client/player slot) -* **[Misc]** Updated Syria terrain parking slots database, the out-of-date database could end up generating aircraft in wrong slots (We are still experiencing issues with somes airbases, such as Khalkhalah though) - -# 2.2.0 - -## Features/Improvements : -* **[Campaign Generator]** Added early warning radar generation -* **[Campaign Generator]** Added scud launcher sites -* **[Cheat Menu]** Added ability to capture base from mission planner -* **[Cheat Menu]** Added ability to show red ATO -* **[Factions]** Added WW2 factions that do not depend on WW2 asset pack -* **[Factions]** Cold War / Middle eastern factions will use Flak sites -* **[Flight Planner]** Flight planner overhaul, with package and TOT system -* **[Flight Planner]** Pick runways and ascent/descent based on headwind -* **[Map]** Added polygon debug mode display -* **[Map]** Highlight the selected flight path on the map -* **[Map]** Improved SAM display settings -* **[Map]** Improved flight plan display settings -* **[Map]** Caucasus and The Channel map use a new system to generate SAM and strike target location to reduce probability of targets generated in the middle of a forests -* **[Misc]** Flexible Dedicated Hosting Options for Mission Files via environment variables -* **[Moddability]** Custom campaigns can be designed through json files -* **[Moddability]** LUA plugins can now be injected into Liberation missions. -* **[Moddability]** Optional Skynet IADS lua plugin now included -* **[New Game]** Starting budget can be freely selected -* **[New Game]** Exanded information for faction and campaign selection in the new game wizard -* **[UI]** Add double and right click actions to many UI elements. -* **[UI]** Add polygon drawing mode for map background -* **[UI]** Added a warning if you press takeoff with no player enabled flights -* **[UI]** Packages and flights now visible in the main window sidebar -* **[Units/Factions]** Added bombers to some coalitions -* **[Units/Factions]** Added support for SU-57 mod by Cubanace -* **[Units]** Added Freya EWR sites to german WW2 factions -* **[Units]** Added support for many bombers (B-52H, B-1B, Tu-22, Tu-142) -* **[Units]** Added support for new P-47 variants - -## Fixes : -* **[Campaign Generator]** Big airbases could end up without any airbase defense. -* **[Campaign generator]** Ship group and offshore buildings should not be generated on land anymore -* **[Flight Planner]** Fix waypoint alitudes for helicopters -* **[Flight Planner]** Fixed CAS aircraft wandering away from frontline -* **[Maps]** Incirlik airbase was missing exclusions zones, so SAMS could end up being generated on the runway -* **[Mission Generator]** Fixed player/client confusion when a flight had only one player slot. -* **[Radios]** Fix A-10C radio -* **[UI]** Many missing unit icons were added -* **[UI]** Missing TER weapons in custom payload now selectable. - -# 2.1.5 - -## Features/Improvements : -* **[Units/Factions]** Enabled EPLRS for ground units that supports it (so they appear on A-10C II TAD and Helmet) - -## Fixes : -* **[UI]** Fixed an issue that prevent saving after aborting a mission -* **[Mission Generator]** Fixed aircraft landing point type being wrong - -# 2.1.4 - -## Fixes : -* **[UI]** Fixed an issue that prevented generating the mission (take off button no working) on old savegames. - -## Features/Improvements : -* **[Units/Factions]** Added A-10C_2 to USA 2005 and Bluefor modern factions -* **[UI]** Limit number of aircraft that can be bought to the number of available parking slots. -* **[Mission Generator]** Use inline loading of the JSON.lua library, and save to either %LIBERATION_EXPORT_DIR%, or to DCS working directory - -## Changes : -* **[Units/Factions]** Bluefor generic factions will now use the new "Combined Joint Task Forces Blue" country in the generated mission instead of "USA" - -## Fixes : -* **[UI]** Fixed icon for Viggen -* **[UI]** Added icons for some ground units -* **[Misc]** Fixed issue with Chinese characters in pydcs preventing generating the mission. (Take Off button not working) (thanks to spark135246) -* **[Misc]** Fixed an error causing with ATC frequency preventing generating the mission. (Take Off button not working) (thanks to danalbert) - -# 2.1.2 - -## Fixes : -* **[Mission Generator]** Fix mission generation issues with radio frequencies (Thanks to contributors davidp57 and danalbert) -* **[Mission Generator]** AI should now properly plan flights for Tornados - -# 2.1.1 - -## Features/Improvements : -* **[Other]** Added an installer option (thanks to contributor parithon) -* **[Kneeboards]** Generate mission kneeboards for player flights. Kneeboards include - airfield/carrier information (ATC frequencies, ILS, TACAN, and runway - assignments), assigned radio channels, waypoint lists, and AWACS/JTAC/tanker - information. (Thanks to contributor danalbert) -* **[Radios]** Allocate separate intra-flight channels for most aircraft to reduce global - chatter. (Thanks to contributor danalbert) -* **[Radios]** Configure radio channel presets for most aircraft. Currently supported are: - * AJS37 - * AV-8B - * F-14B - * F-16C - * F/A-18C - * JF-17 - * M-2000C (Thanks to contributor danalbert) -* **[Base Menu]** Added possibility to repair destroyed SAM and base defenses units for the player (Click on a SAM site to fix it) -* **[Base Menu]** Added possibility to buy/sell/replace SAM units -* **[Map]** Added recon images for buildings on strike targets, click on a Strike target to get detailled informations -* **[Units/Factions]** Added F-16C to USA 1990 -* **[Units/Factions]** Added MQ-9 Reaper as CAS unit for USA 2005 -* **[Units/Factions]** Added Mig-21, Mig-23, SA-342L to Syria 2011 -* **[Cheat Menu]** Added buttons to remove money - -## Fixed issues : -* **[UI/UX]** Spelling issues (Thanks to contributor steveveepee) -* **[Campaign Generator]** LHA was placed on land in Syrian Civil War campaign -* **[Campaign Generator]** Fixed inverted configuration for Syria full map -* **[Campaign Generator]** Syria "Inherent Resolve" campaign, added Incirlik Air Base -* **[Mission Generator]** AH-1W was not used by AI to generate CAS mission by default -* **[Mission Generator]** Fixed F-16C targeting pod not being added to payload -* **[Mission Generator]** AH-64A and AH-64D payloads fix. -* **[Units/Factions]** China will use KJ-2000 as awacs instead of A-50 - -# 2.1.0 - -## Features/Improvements : - -* **[Campaign Generator]** Added Syria map -* **[Campaign Generator]** Added 5 campaigns for the Syria map -* **[Campaign Generator]** Added 2 small scale campaign for Persian Gulf map -* **[Units/Factions]** Added factions for Syria map : Syria 2011, Arab Armies 1982, 1973, 1968, 1948, Israel 1982, 1973, 1948 -* **[Base Menu]** Budget is visible in recruitment menu. (Thanks to Github contributor root0fall) -* **[Misc]** Added error message in mission when the state file can not be written -* **[Units/Factions]** China, Pakistan, UAE will now use the new WingLoong drone as JTAC instead of the MQ-9 Reaper -* **[Units/Factions]** Minor changes to Syria 2011 and Turkey 2005 factions -* **[UI]** Version number is shown in about dialog - -## Fixed issues : - -* **[Mission Generator]** Caucasus terrain improvement on exclusions zone (added forests between Vaziani and Beslan to exclusion zones) -* **[Mission Generator]** The first unit of every base defenses group could not be controlled with Combined Arms. -* **[Mission Generator]** Reduced generated helicopter altitude for CAS missions -* **[Mission Generator]** F-16C default CAS payload was asymmetric, fixed. -* **[Mission Generator]** AH-1W couldn't be bought, and added default payloads. -* **[UI/UX]** Fixed Mi-28N missing thumbnail -* **[UI/UX]** Fixed list of flights not refreshing when changing the mission departure (T+). - -# 2.0.11 - -## Features/Improvements : - -* **[Units/Factions]** Added Mig-31, Su-30, Mi-24V, Mi-28N to Russia 2010 faction. -* **[Units/Factions]** Added F-15E to USA 2005 and USA 1990 factions. -* **[Mission Generator]** Added a parameter to choose whether the JTACs should use smoke markers or not - -## Fixed issues : - -* **[Units/Factions]** Fixed big performance issue in new release UI that occurred only when running the .exe -* **[Units/Factions]** Fixed mission generation not working with Libya faction -* **[Units/Factions]** Fixed OH-58D not being used by AI -* **[Units/Factions]** Typo in UK 1990 name (fixed by bwRavencl) -* **[Units/Factions]** Fixed Tanker Tacan channel not being the same as the briefing one. (Sorry) -* **[Mission Generator]** Neutral airbases services will now be disabled. (Not possible to refuel or re-arm there) -* **[Mission Generator]** AI will be configured to limit afterburner usage -* **[Mission Generator]** JTAC will not use laser codes above 1688 anymore -* **[Mission Generator]** JTAC units were misconfigured and would not be invisible/immortal. -* **[Mission Generator]** Increased JTAC status message duration to 25s, so you have more time to enter coordinates; -* **[Mission Generator]** Destroyed units carcass will not appear on airfields to avoid having a destroyed vehicle blocking a runway or taxiway. - - -# 2.0.10 - -## Features/Improvements : -* **[Misc]** Now possible to save game in a different file, and to open DCS Liberation savegame files. (You are not restricted to a single save file anymore) -* **[UI/UX]** New dark UI Theme and default theme improvement by Deus -* **[UI/UX]** New "satellite" map backgrounds -* **[UX]** Base menu is opened with a single mouse click -* **[Units/Factions/Mods]** Added Community A-4E-C support for faction Bluefor Cold War -* **[Units/Factions/Mods]** Added MB-339PAN support for faction Bluefor Cold War -* **[Units/Factions/Mods]** Added Rafale AI mod support -* **[Units/Factions/Mods]** Added faction "France Modded" with units from frenchpack v3.5 mod -* **[Units/Factions/Mods]** Added faction "Insurgent modded" with Insurgent units from frenchpack v3.5 mod (Toyota truck) -* **[Units/Factions/Mods]** Added factions Canada 2005, Australia 2005, Japan 2005, USA Aggressors, PMC -* **[New Game Wizard]** Added the list of required mods for modded factions. -* **[New Game Wizard]** No more RED vs BLUE opposing faction restrictions. -* **[New Game Wizard]** New campaign generation settings added : No aircraft carrier, no lha, no navy, invert map starting positions. -* **[Mission Generator]** Artillery units will start firing mission after a random delay. It should reduces lag spikes induced by artillery strikes by spreading them out. -* **[Mission Generator]** Ground units will retreat after taking too much casualties. Artillery units will retreat if engaged. -* **[Mission Generator]** The briefing will now contain the carrier ATC frequency -* **[Mission Generator]** The briefing contains a small situation update. -* **[Mission Generator]** Previously destroyed units are visible in the mission. (And added a performance settings to disable this behaviour) -* **[Mission Generator]*c* Basic JTAC on Frontlines -* **[Campaign Generator]** Added Tarawa in caucasus campaigns -* **[Campaign Generator]** Tuned the various existing campaign parameters -* **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater - -## Fixed issues : -* **[Mission Generator]** Carrier will sail into the wind, not in the same direction -* **[Mission Generator]** Carrier cold start was not working (flight was starting warm even when cold was selected) -* **[Mission Generator]** Carrier group ships are more spread out -* **[Mission Generator]** Fixed wrong radio frequency for german WW2 warbirds -* **[Mission Generator]** Fixed FW-190A8 spawning with bomb rack for CAP missions -* **[Mission Generator]** Fixed A-20G spawning with no payload -* **[Mission Generator]** Fixed Su-33 spawning too heavy to take off from carrier -* **[Mission Generator]** Fixed Harrier AV-8B spawning too heavy to take off from tarawa -* **[Mission Generator]** Base defense units were not controllable with Combined Arms -* **[Mission Generator]** Tanker speed was too low -* **[Mission Generator]** Tanker TACAN settings were wrong -* **[Mission Generator]** AI aircraft should start datalink ON (EPLRS) -* **[Mission Generator]** Base defense units should not spawn on runway and or taxyway. (The chance for this to happen should now be really really low) -* **[Mission Generator]** Fixed all flights starting "In flight" after playing a few missions (parking slot reset issue) -* **[Mission Script/Performance]** Mission lua script will not listen to weapons fired event anymore and register every fired weapons. This should improve performance especially in WW2 scenarios or when rocket artillery is firing. -* **[Campaign Generator]** Carrier name will now not appear for faction who do not have carriers -* **[Campaign Generator]** SA-10 sites will now have a tracking radar. -* **[Units/Factions]** Remove JF-17 from USA 2005 faction -* **[Units/Factions]** Remove AJS-37 from Russia 2010 -* **[Units/Factions]** Removed Oliver Hazard Perry from cold war factions (too powerful sam system for the era) -* **[Bug]** On the persian gulf full map campaign, the two carriers were sharing the same id, this was causing a lot of bugs -* **[Performance]** Tuned the culling setting so that you cannot run into situation where no friendly or enemy AI flights are generated -* **[Other]** Application doesn't gracefully exit. -* **[Other]** Other minor fixes, and multiples factions small changes - -# 2.0 RC 9 - -## Features/Improvements : -* **[UI/UX]** New icons from contributor Deus - -## Fixed issues : -* **[Mission Generator]** Carrier TACAN was wrongfully set up as an A/A TACAN -* **[Campaign Generator]** Fixed issue with Russian navy group generator causing a random crash on campaign creation. - -# 2.0 RC 8 - -## Fixed issues : -* **[Mission Generator]** Frequency for P-47D-30 changed to 124Mhz (Generated mission with 251Mhz would not work) -* **[Mission Generator]** Reduced the maximum number of uboat per generated group -* **[Mission Generator]** Fixed an issue with the WW2 LST groups (superposed units). -* **[UI]** Fixed issue with the zoom - -# 2.0 RC 7 - -## Features/Improvements : - -* **[Units/Factions]** Added P-47D-30 for factions allies_1944 -* **[Units/Factions]** Added factions : Bluefor Coldwar, Germany 1944 Easy - -* **[Campaign/Map]** Added a campaign in the Channel map -* **[Campaign/Map]** Changed the Normandy campaign map -* **[Campaign/Map]** Added new campaign Normandy Small - -* **[Mission Generator]** AI Flight generator has been reworked -* **[Mission Generator]** Add PP points for JF-17 on STRIKE missions -* **[Mission Generator]** Add ST point for F-14B on STRIKE missions -* **[Mission Generator]** Flights with client slots will never be delayed -* **[Mission Generator]** AI units can start from parking (With a new setting in Settings Window to disable it) -* **[Mission Generator]** Tacan for carrier will only be in Mode X from now -* **[Mission Generator]** RTB waypoints for autogenerated flights - -* **[Flight Planner]** Added CAS mission generator -* **[Flight Planner]** Added CAP mission generator -* **[Flight Planner]** Added SEAD mission generator -* **[Flight Planner]** Added STRIKE mission generator -* **[Flight Planner]** Added buttons to add autogenerated waypoints (ASCEND, DESCEND, RTB) -* **[Flight Planner]** Improved waypoint list -* **[Flight Planner]** WW2 factions uses different parameters for flight planning. - -* **[Settings]** Added settings to disallow external views -* **[Settings]** Added settings to choose F10 Map mode (All, Allies only, Player only, Fog of War, Map Only) -* **[Settings]** Added settings to choose whether to auto-generate objective marks on the F10 map - -* **[Info Panel]** Added information about destroyed buildings in info panel -* **[Info Panel]** Added information about destroyed units at SAM site in info panel -* **[Debriefing]** Added information about units destroyed outside the frontline in the debriefing window -* **[Debriefing]** Added destroyed buildings in the debriefing window - -* **[Map]** Tooltip now contains the list of building for Strike targets on the map -* **[Map]** Added "Oil derrick" building -* **[Map]** Added "ww2 bunker" building (WW2) -* **[Map]** Added "ally camp" building (WW2) -* **[Map]** Added "V1 Site" (WW2) - -* **[Misc]** Made it possible to setup DCS Saved Games directory and DCS installation directory manually at first start -* **[Misc]** Added culling performance settings - -## Fixed issues : - -* **[Units/Factions]** Replaced S3-B Tanker by KC130 for most factions (More fuel) -* **[Units/Factions]** WW2 factions will not have offshore oil station and other modern buildings generated. No more third-reich operated offshore stations will spawn on normandy's coast. -* **[Units/Factions]** Aircraft carrier will try to move in the wind direction -* **[Units/Factions]** Missing icons added for some aircraft - -* **[Mission Generator]** When playing as RED the activation trigger would not be properly generated -* **[Mission Generator]** FW-190A8 is now properly considered as a flyable aircraft -* **[Mission Generator]** Changed "strike" payload for Su-24M that was ineffective -* **[Mission Generator]** Changed "strike" payload for JF-17 to use LS-6 bombs instead of GBU -* **[Mission Generator]** Change power station template. (Buildings could end up superposed). - -* **[Maps/Campaign]** Now using Vasiani airbase instead of Soganlung airport in Caucasus campaigns (more parking slot) -* **[Info Panel]** Message displayed on base capture event stated that the enemy captured an airbase, while it was the player who captured it. -* **[Map View]** Graphical glitch on map when one building of an objective was destroyed, but not the others -* **[Mission Planner]** The list of flights was not updated on departure time change. - - -# 2.0 RC 6 - -Saves file from RC5 are not compatible with the new version. -Sorry :( - -## Features/Improvements : -* **[Units/Factions]** Supercarrier support (You have to go to settings to enable it, if you have the supercarrier module) -* **[Units/Factions]** Added 'Modern Bluefor' factions, containing all most popular DCS flyable units -* **[Units/Factions]** Factions US 2005 / 1990 will now sometimes have Arleigh Burke class ships instead of Perry as carrier escorts -* **[Units/Factions]** Added support for newest WW2 Units -* **[Campaign logic]** When a base is captured, refill the "base defenses" group with units for the new owner. -* **[Mission Generator]** Carrier ICLS channel will now be configured (check your briefing) -* **[Mission Generator]** SAM units will spawn on RED Alarm state -* **[Mission Generator]** AI Flight planner now creates its own STRIKE flights -* **[Mission Generator]** AI units assigned to Strike flight will now actually engage the buildings they have been assigned. -* **[Mission Generator]** Added performance settings to allow disabling : smoke, artillery strike, moving units, infantry, SAM Red alert mode. -* **[Mission Generator]** Using Late Activation & Trigger in attempt to improve performance & reduce stutter (Previously they were spawned through 'ETA' feature) -* **[UX]** : Improved flight selection behaviour in the Mission Planning Window - -## Fixed issues : -* **[Mission Generator]** Payloads were not correctly assigned in the release version. -* **[Mission Generator]** Game generation does not work when "no night mission" settings was selected and the current time was "day" -* **[Mission Generator]** Game generation does not work when the player selected faction has no AWACS -* **[Mission Generator]** Planned flights will spawn even if their home base has been captured or is being contested by enemy ground units. -* **[Campaign Generator]** Base defenses would not be generated on Normandy map and in some rare cases on others maps as well -* **[Mission Planning]** CAS waypoints created from the "Predefined waypoint selector" would not be at the exact location of the frontline -* **[Naming]** CAP mission flown from airbase are not named BARCAP anymore (CAP from carrier is still named BARCAP) diff --git a/client/.gitignore b/client/.gitignore deleted file mode 100644 index 96f008ff7..000000000 --- a/client/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -.vscode/settings.json -.vscode/tasks.json diff --git a/client/.vscode/launch.json b/client/.vscode/launch.json deleted file mode 100644 index 7f8319357..000000000 --- a/client/.vscode/launch.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "configurations": [ - { - "type": "pwa-chrome", - "name": "http://localhost:3000", - "request": "launch", - "url": "http://localhost:3000" - } - ] -} \ No newline at end of file diff --git a/client/README.md b/client/README.md deleted file mode 100644 index f9b5f8bac..000000000 --- a/client/README.md +++ /dev/null @@ -1,76 +0,0 @@ -# DCS Liberation Client - -This is a React app for the front-end of DCS Liberation. It is a work in -progress that just barely implements the map. This is not useful for players -yet. - -For development, set the following environment variables when launching DCS -Liberation (the Qt UI): - -- `CORS_ALLOW_DEBUG_SERVER=true` - - This will allow the front-end to make requests to the server, as long as the - front-end is running on http://localhost:3000. - -Then, run `npm start` to start the development server. Launch the Qt UI with -`--new-map --dev` to connect the webview to the development server, or navigate -to http://localhost:3000 in your browser. - -## Regenerating the API stubs - -The backend uses FastAPI which exposes `/openapi.json`. This is consumed by -`@rtk-query/codegen-openapi` to automatically generate the API stubs in -`src/api/liberationApi.ts`. - -If you make a change to the API surface the typescript API will need to be -regenerated. To do this, first launch Liberation (to start the backend) and run - -```powershell -npm run regenerate-api -``` - -See https://redux-toolkit.js.org/rtk-query/usage/code-generation for more -information. - -## Available Scripts - -In the project directory, you can run: - -### `npm start` - -Runs the app in the development mode.
-Open [http://localhost:3000](http://localhost:3000) to view it in the browser. - -The page will reload if you make edits.
-You will also see any lint errors in the console. - -### `npm test` - -Launches the test runner in the interactive watch mode.
-See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. - -### `npm run build` - -Builds the app for production to the `build` folder.
-It correctly bundles React in production mode and optimizes the build for the best performance. - -The build is minified and the filenames include the hashes.
-Your app is ready to be deployed! - -See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. - -### `npm run eject` - -**Note: this is a one-way operation. Once you `eject`, you can’t go back!** - -If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. - -Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. - -You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. - -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). diff --git a/client/main.js b/client/main.js deleted file mode 100644 index b579c5981..000000000 --- a/client/main.js +++ /dev/null @@ -1,57 +0,0 @@ -const path = require("path"); - -const { app, BrowserWindow } = require("electron"); -const isDev = require("electron-is-dev"); -const windowStateKeeper = require("electron-window-state"); - -function createWindow() { - let mainWindowState = windowStateKeeper({ - defaultWidth: 1000, - defaultHeight: 800, - }); - - // Create the browser window. - const win = new BrowserWindow({ - x: mainWindowState.x, - y: mainWindowState.y, - width: mainWindowState.width, - height: mainWindowState.height, - show: false, - webPreferences: { - nodeIntegration: true, - }, - }); - mainWindowState.manage(win); - - // and load the index.html of the app. - // win.loadFile("index.html"); - win.loadURL( - isDev - ? "http://localhost:3000" - : `file://${path.join(__dirname, "../build/index.html")}` - ); - // Open the DevTools. - if (isDev) { - win.webContents.openDevTools({ mode: "detach" }); - } -} - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.whenReady().then(createWindow); - -// Quit when all windows are closed, except on macOS. There, it's common -// for applications and their menu bar to stay active until the user quits -// explicitly with Cmd + Q. -app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - app.quit(); - } -}); - -app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } -}); diff --git a/client/openapi-config.ts b/client/openapi-config.ts deleted file mode 100644 index 96512958e..000000000 --- a/client/openapi-config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ConfigFile } from "@rtk-query/codegen-openapi"; - -const config: ConfigFile = { - schemaFile: "http://[::1]:16880/openapi.json", - apiFile: "./src/api/baseApi.ts", - apiImport: "baseApi", - outputFile: "./src/api/_liberationApi.ts", - exportName: "_liberationApi", - hooks: true, -}; - -export default config; diff --git a/client/package-lock.json b/client/package-lock.json deleted file mode 100644 index e327a33ad..000000000 --- a/client/package-lock.json +++ /dev/null @@ -1,37292 +0,0 @@ -{ - "name": "liberation-client", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "liberation-client", - "version": "0.1.0", - "license": "LGPL-3.0-or-later", - "dependencies": { - "@reduxjs/toolkit": "^1.8.5", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", - "@types/jest": "^29.1.2", - "@types/node": "^18.8.3", - "@types/react": "^18.0.21", - "@types/react-dom": "^18.0.6", - "@types/react-redux": "^7.1.24", - "axios": "^1.6.0", - "electron-window-state": "^5.0.3", - "esri-leaflet": "^3.0.8", - "leaflet": "^1.9.2", - "leaflet-ruler": "^1.0.0", - "milsymbol": "^2.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-esri-leaflet": "^2.0.1", - "react-leaflet": "^4.1.0", - "react-redux": "^8.0.4", - "redux-logger": "^3.0.6", - "typescript": "~4.8.4" - }, - "devDependencies": { - "@rtk-query/codegen-openapi": "^1.0.0", - "@trivago/prettier-plugin-sort-imports": "^4.2.1", - "@types/leaflet": "^1.8.0", - "@types/redux-logger": "^3.0.9", - "@types/websocket": "^1.0.5", - "electron": "^22.3.25", - "electron-is-dev": "^2.0.0", - "generate-license-file": "^2.0.0", - "jest-transform-stub": "^2.0.0", - "license-checker": "^25.0.1", - "msw": "^1.2.2", - "react-scripts": "5.0.1", - "ts-node": "^10.9.1", - "wait-on": "^6.0.1" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" - }, - "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz", - "integrity": "sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==", - "dev": true, - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.13.1" - } - }, - "node_modules/@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "dev": true - }, - "node_modules/@apidevtools/swagger-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz", - "integrity": "sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==", - "dev": true, - "dependencies": { - "@apidevtools/json-schema-ref-parser": "9.0.6", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.6.3", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.1" - }, - "peerDependencies": { - "openapi-types": ">=7" - } - }, - "node_modules/@apidevtools/swagger-parser/node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@apidevtools/swagger-parser/node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/@apidevtools/swagger-parser/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", - "dev": true, - "dependencies": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || >=14.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@babel/eslint-parser/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", - "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers/node_modules/@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.6.tgz", - "integrity": "sha512-OBv9VkyyKtsHZiHLoSfCn+h6yU7YKX8nrs32xUmOa1SRSk+t03FosB6fBZ0Yz4BpD1WV7l73Nsad+2Tz7APpqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz", - "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "dev": true, - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", - "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.3.tgz", - "integrity": "sha512-z6fnuK9ve9u/0X0rRvI9MY0xg+DOUaABDYOe+/SQTxtlptaBB/V9JIUxJn6xp3lMBeb9qe8xSFmHU35oZDXD+w==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-typescript": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", - "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-typescript": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", - "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", - "dev": true, - "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==", - "dev": true - }, - "node_modules/@csstools/postcss-color-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.0.2.tgz", - "integrity": "sha512-uayvFqfa0hITPwVduxRYNL9YBD/anTqula0tu2llalaxblEd7QPuETSN3gB5PvTYxSfd0d8kS4Fypgo5JaUJ6A==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-font-format-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.0.tgz", - "integrity": "sha512-oO0cZt8do8FdVBX8INftvIA4lUrKUSCcWUf9IwH9IPWOgKT22oAZFXeHLoDK7nhB2SmkNycp5brxfNMRLIhd6Q==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@csstools/postcss-hwb-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.0.tgz", - "integrity": "sha512-VSTd7hGjmde4rTj1rR30sokY3ONJph1reCBTUXqeW1fKwETPy1x4t/XIeaaqbMbC5Xg4SM/lyXZ2S8NELT2TaA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@csstools/postcss-ic-unit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.0.tgz", - "integrity": "sha512-i4yps1mBp2ijrx7E96RXrQXQQHm6F4ym1TOD0D69/sjDjZvQ22tqiEvaNw7pFZTUO5b9vWRHzbHzP9+UKuw+bA==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@csstools/postcss-is-pseudo-class": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.0.tgz", - "integrity": "sha512-WnfZlyuh/CW4oS530HBbrKq0G8BKl/bsNr5NMFoubBFzJfvFRGJhplCgIJYWUidLuL3WJ/zhMtDIyNFTqhx63Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-normalize-display-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.0.tgz", - "integrity": "sha512-bX+nx5V8XTJEmGtpWTO6kywdS725t71YSLlxWt78XoHUbELWgoCXeOFymRJmL3SU1TLlKSIi7v52EWqe60vJTQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@csstools/postcss-oklab-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.0.1.tgz", - "integrity": "sha512-Bnly2FWWSTZX20hDJLYHpurhp1ot+ZGvojLOsrHa9frzOVruOv4oPYMZ6wQomi9KsbZZ+Af/CuRYaGReTyGtEg==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.2.0.tgz", - "integrity": "sha512-YLpFPK5OaLIRKZhUfnrZPT9s9cmtqltIOg7W6jPcxmiDpnZ4lk+odfufZttOAgcg6IHWvNLgcITSLpJxIQB/qQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz", - "integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@exodus/schemasafe": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz", - "integrity": "sha512-+1mBLsa+vvlV0lwEAP1hwgmOPkjMnoJ8hyCMfCCJga0sVDwDzrPJjnxZwdDaUmOh/vbFHQGBTk+FxsVjoI/CjQ==", - "dev": true - }, - "node_modules/@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", - "dev": true - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/console/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/console/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/console/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/core/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/core/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.1.2.tgz", - "integrity": "sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==", - "dependencies": { - "jest-get-type": "^29.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils/node_modules/jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/reporters/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/reporters/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/reporters/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/reporters/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "dependencies": { - "@sinclair/typebox": "^0.24.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/source-map/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/transform/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/transform/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/transform/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/transform/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/transform/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@jest/transform/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true - }, - "node_modules/@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "peer": true, - "dependencies": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - }, - "bin": { - "geojson-rewind": "geojson-rewind" - } - }, - "node_modules/@mapbox/geojson-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", - "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==", - "peer": true - }, - "node_modules/@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@mapbox/mapbox-gl-supported": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", - "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", - "peer": true, - "peerDependencies": { - "mapbox-gl": ">=0.32.1 <2.0.0" - } - }, - "node_modules/@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "peer": true - }, - "node_modules/@mapbox/tiny-sdf": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", - "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==", - "peer": true - }, - "node_modules/@mapbox/unitbezier": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", - "peer": true - }, - "node_modules/@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "peer": true, - "dependencies": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "node_modules/@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@mswjs/cookies": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", - "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", - "dev": true, - "dependencies": { - "@types/set-cookie-parser": "^2.4.0", - "set-cookie-parser": "^2.4.6" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.17.9", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.9.tgz", - "integrity": "sha512-4LVGt03RobMH/7ZrbHqRxQrS9cc2uh+iNKSj8UWr8M26A2i793ju+csaB5zaqYltqJmA2jUq4VeYfKmVqvsXQg==", - "dev": true, - "dependencies": { - "@open-draft/until": "^1.0.3", - "@types/debug": "^4.1.7", - "@xmldom/xmldom": "^0.8.3", - "debug": "^4.3.3", - "headers-polyfill": "^3.1.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.2.4", - "web-encoding": "^1.1.5" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@mswjs/interceptors/node_modules/strict-event-emitter": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", - "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", - "dev": true, - "dependencies": { - "events": "^3.3.0" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "dependencies": { - "eslint-scope": "5.1.1" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@open-draft/until": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", - "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", - "dev": true - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", - "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", - "dev": true, - "dependencies": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.8.1", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">= 10.13" - }, - "peerDependencies": { - "@types/webpack": "4.x || 5.x", - "react-refresh": ">=0.10.0 <1.0.0", - "sockjs-client": "^1.4.0", - "type-fest": ">=0.17.0 <3.0.0", - "webpack": ">=4.43.0 <6.0.0", - "webpack-dev-server": "3.x || 4.x", - "webpack-hot-middleware": "2.x", - "webpack-plugin-serve": "0.x || 1.x" - }, - "peerDependenciesMeta": { - "@types/webpack": { - "optional": true - }, - "sockjs-client": { - "optional": true - }, - "type-fest": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - }, - "webpack-hot-middleware": { - "optional": true - }, - "webpack-plugin-serve": { - "optional": true - } - } - }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@reduxjs/toolkit": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.5.tgz", - "integrity": "sha512-f4D5EXO7A7Xq35T0zRbWq5kJQyXzzscnHKmjnu2+37B3rwHU6mX9PYlbfXdnxcY6P/7zfmjhgan0Z+yuOfeBmA==", - "dependencies": { - "immer": "^9.0.7", - "redux": "^4.1.2", - "redux-thunk": "^2.4.1", - "reselect": "^4.1.5" - }, - "peerDependencies": { - "react": "^16.9.0 || ^17.0.0 || ^18", - "react-redux": "^7.2.1 || ^8.0.2" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - }, - "react-redux": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "@types/babel__core": "^7.1.9", - "rollup": "^1.20.0||^2.0.0" - }, - "peerDependenciesMeta": { - "@types/babel__core": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" - } - }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" - } - }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@rtk-query/codegen-openapi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rtk-query/codegen-openapi/-/codegen-openapi-1.0.0.tgz", - "integrity": "sha512-mptXwJVtMLozWFSqxm7WKY6K8duWLsPgjmkGjqaEqo5qEWJlARur6SHoqugKh3fHSM7vPaCS3VcWJ5RCYjup9Q==", - "dev": true, - "dependencies": { - "@apidevtools/swagger-parser": "^10.0.2", - "@rtk-query/oazapfts-patched": "^3.6.0-2", - "commander": "^6.2.0", - "prettier": "^2.2.1", - "semver": "^7.3.5", - "swagger2openapi": "^7.0.4", - "typescript": ">=4.1 <=4.5" - }, - "bin": { - "rtk-query-codegen-openapi": "lib/bin/cli.js" - } - }, - "node_modules/@rtk-query/codegen-openapi/node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@rtk-query/codegen-openapi/node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/@rtk-query/oazapfts-patched": { - "version": "3.6.0-2", - "resolved": "https://registry.npmjs.org/@rtk-query/oazapfts-patched/-/oazapfts-patched-3.6.0-2.tgz", - "integrity": "sha512-9Y9j8BOvmb7WStrY2SomAk8syoAc8/8/EDS8OybG7G2mxy5aWH9qxNZgGxx9ODR4lQwbglan4+kTq0X6KqHUYA==", - "dev": true, - "dependencies": { - "@apidevtools/swagger-parser": "^10.0.1", - "lodash": "^4.17.20", - "minimist": "^1.2.5", - "swagger2openapi": "^7.0.7", - "typescript": "^4.1.2" - }, - "bin": { - "oazapfts": "lib/codegen/cli.js" - } - }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "node_modules/@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "dev": true - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "node_modules/@sinclair/typebox": { - "version": "0.24.44", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", - "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==" - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, - "dependencies": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "node_modules/@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "dev": true, - "dependencies": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "dev": true, - "dependencies": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.12.6" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/gregberge" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@terraformer/arcgis": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@terraformer/arcgis/-/arcgis-2.1.0.tgz", - "integrity": "sha512-eKTvNXze2Fo7vAEjvJFIGn5QdU0OP4aD9DuT/uTBLRM1QS+ju7KtPITbVW+xgCviHLnOVeFQ1UsIs9kjkakD4g==", - "dependencies": { - "@terraformer/common": "^2.0.7" - } - }, - "node_modules/@terraformer/common": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@terraformer/common/-/common-2.0.7.tgz", - "integrity": "sha512-8bl+/JT0Rw6FYe2H3FfJS8uQwgzGl+UHs+8JX0TQLHgA4sMDEwObbMwo0iP3FVONwPXrPHEpC5YH7Grve0cl9A==" - }, - "node_modules/@testing-library/dom": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.3.tgz", - "integrity": "sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/dom/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@testing-library/dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "dependencies": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=8", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@testing-library/jest-dom/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@trivago/prettier-plugin-sort-imports": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz", - "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==", - "dev": true, - "dependencies": { - "@babel/generator": "7.17.7", - "@babel/parser": "^7.20.5", - "@babel/traverse": "7.23.2", - "@babel/types": "7.17.0", - "javascript-natural-sort": "0.7.1", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "@vue/compiler-sfc": "3.x", - "prettier": "2.x - 3.x" - }, - "peerDependenciesMeta": { - "@vue/compiler-sfc": { - "optional": true - } - } - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" - }, - "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dev": true, - "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "node_modules/@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.8", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", - "dev": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "node_modules/@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", - "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", - "dev": true - }, - "node_modules/@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jest/node_modules/@jest/types": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.1.2.tgz", - "integrity": "sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@types/jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/@types/jest/node_modules/diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/expect": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.1.2.tgz", - "integrity": "sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==", - "dependencies": { - "@jest/expect-utils": "^29.1.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.1.2", - "jest-message-util": "^29.1.2", - "jest-util": "^29.1.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@types/jest/node_modules/jest-diff": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.1.2.tgz", - "integrity": "sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.1.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-matcher-utils": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz", - "integrity": "sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.1.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.1.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-message-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", - "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.1.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.1.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/jest-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.1.2.tgz", - "integrity": "sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==", - "dependencies": { - "@jest/types": "^29.1.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/pretty-format": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", - "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", - "dependencies": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@types/jest/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@types/jest/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/@types/jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@types/js-levenshtein": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", - "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/leaflet": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.8.0.tgz", - "integrity": "sha512-+sXFmiJTFdhaXXIGFlV5re9AdqtAODoXbGAvxx02e5SHXL3ir7ClP5J7pahO8VmzKY3dth4RUS1nf2BTT+DW1A==", - "dev": true, - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==" - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", - "dev": true - }, - "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" - }, - "node_modules/@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "node_modules/@types/react": { - "version": "18.0.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", - "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-redux": { - "version": "7.1.24", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", - "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", - "dependencies": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "node_modules/@types/redux-logger": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/redux-logger/-/redux-logger-3.0.9.tgz", - "integrity": "sha512-cwYhVbYNgH01aepeMwhd0ABX6fhVB2rcQ9m80u8Fl50ZODhsZ8RhQArnLTkE7/Zrfq4Sz/taNoF7DQy9pCZSKg==", - "dev": true, - "dependencies": { - "redux": "^4.0.0" - } - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/responselike": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", - "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "node_modules/@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "node_modules/@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dev": true, - "dependencies": { - "@types/express": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/set-cookie-parser": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", - "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" - }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.2.tgz", - "integrity": "sha512-vehbtyHUShPxIa9SioxDwCvgxukDMH//icJG90sXQBUm5lJOHLT5kNeU9tnivhnA/TkOFMzGIXN2cTc4hY8/kg==", - "dependencies": { - "@types/jest": "*" - } - }, - "node_modules/@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true - }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, - "node_modules/@types/websocket": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", - "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/ws": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.1.tgz", - "integrity": "sha512-UxlLOfkuQnT2YSBCNq0x86SGOUxas6gAySFeDe2DcnEnA8655UIPoCDorWZCugcvKIL8IUI4oueUfJ1hhZSE2A==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" - }, - "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.39.0.tgz", - "integrity": "sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/type-utils": "5.39.0", - "@typescript-eslint/utils": "5.39.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.39.0.tgz", - "integrity": "sha512-n5N9kG/oGu2xXhHzsWzn94s6CWoiUj59FPU2dF2IQZxPftw+q6Jm5sV2vj5qTgAElRooHhrgtl2gxBQDCPt6WA==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.39.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", - "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.39.0.tgz", - "integrity": "sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.39.0", - "@typescript-eslint/utils": "5.39.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", - "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", - "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.39.0.tgz", - "integrity": "sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", - "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.39.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.8.tgz", - "integrity": "sha512-0LNz4EY8B/8xXY86wMrQ4tz6zEHZv9ehFMJPm8u2gq5lQ71cfRKdaKyxfJAx5aUoyzx0qzgURblTisPGgz3d+Q==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "dev": true, - "optional": true - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "dependencies": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - } - }, - "node_modules/acorn-node/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", - "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "engines": { - "node": ">=8.9" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - }, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "node_modules/array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true - }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axe-core": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", - "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/axios": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", - "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dev": true, - "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-jest/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/babel-jest/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/babel-jest/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/babel-jest/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-jest/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-loader/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "dev": true, - "peerDependencies": { - "@babel/core": "^7.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", - "dev": true - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "node_modules/bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", - "dev": true, - "dependencies": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "dev": true, - "optional": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", - "dev": true, - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 10.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", - "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-pure": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", - "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-blank-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "dev": true, - "dependencies": { - "timsort": "^0.3.0" - }, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-has-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-loader": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.6.0.tgz", - "integrity": "sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==", - "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.5", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", - "dev": true, - "dependencies": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "@parcel/css": { - "optional": true - }, - "clean-css": { - "optional": true - }, - "csso": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/css-minimizer-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "dev": true, - "bin": { - "css-prefers-color-scheme": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" - }, - "node_modules/csscolorparser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", - "peer": true - }, - "node_modules/cssdb": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-6.4.0.tgz", - "integrity": "sha512-8NMWrur/ewSNrRNZndbtOTXc2Xb2b+NCTPHj8VErFYvJUlgsMAiBGaFaxG6hjy9zbCjj2ZLwSQrMM+tormO8qA==", - "dev": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.17.tgz", - "integrity": "sha512-fmjLP7k8kL18xSspeXTzRhaFtRI7DL9b8IcXR80JgtnWBpvAzHT7sCR/6qdn0tnxIaINUN6OEQu83wF57Gs3Xw==", - "dev": true, - "dependencies": { - "cssnano-preset-default": "^5.1.12", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.12.tgz", - "integrity": "sha512-rO/JZYyjW1QNkWBxMGV28DW7d98UDLaF759frhli58QFehZ+D/LSmwQ2z/ylBAe2hUlsIWTq6NYGfQPq65EF9w==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.2", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.5", - "postcss-convert-values": "^5.0.4", - "postcss-discard-comments": "^5.0.3", - "postcss-discard-duplicates": "^5.0.3", - "postcss-discard-empty": "^5.0.3", - "postcss-discard-overridden": "^5.0.4", - "postcss-merge-longhand": "^5.0.6", - "postcss-merge-rules": "^5.0.6", - "postcss-minify-font-values": "^5.0.4", - "postcss-minify-gradients": "^5.0.6", - "postcss-minify-params": "^5.0.5", - "postcss-minify-selectors": "^5.1.3", - "postcss-normalize-charset": "^5.0.3", - "postcss-normalize-display-values": "^5.0.3", - "postcss-normalize-positions": "^5.0.4", - "postcss-normalize-repeat-style": "^5.0.4", - "postcss-normalize-string": "^5.0.4", - "postcss-normalize-timing-functions": "^5.0.3", - "postcss-normalize-unicode": "^5.0.4", - "postcss-normalize-url": "^5.0.5", - "postcss-normalize-whitespace": "^5.0.4", - "postcss-ordered-values": "^5.0.5", - "postcss-reduce-initial": "^5.0.3", - "postcss-reduce-transforms": "^5.0.4", - "postcss-svgo": "^5.0.4", - "postcss-unique-selectors": "^5.0.4" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.2.tgz", - "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/csso/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "node_modules/deep-diff": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", - "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=" - }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "dependencies": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dev": true, - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "dependencies": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - }, - "bin": { - "detective": "bin/detective.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.12.tgz", - "integrity": "sha512-gQ2mON6fLWZeM8ubjzL7RtMeHS/g8hb82j4MjHmcQECD7pevWsMlhqwp9BjIRrQvmyJMMyv/XiO1cXzeFlUw4g==" - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "peer": true - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", - "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron": { - "version": "22.3.25", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.25.tgz", - "integrity": "sha512-AjrP7bebMs/IPsgmyowptbA7jycTkrJC7jLZTb5JoH30PkBC6pZx/7XQ0aDok82SsmSiF4UJDOg+HoLrEBiqmg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^16.11.26", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-is-dev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz", - "integrity": "sha512-3X99K852Yoqu9AcW50qz3ibYBWY79/pBhlMCab8ToEWS48R0T9tyxRiQhwylE7zQdXrMnx2JKqUJyMPmt5FBqA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.275", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.275.tgz", - "integrity": "sha512-aJeQQ+Hl9Jyyzv4chBqYJwmVRY46N5i2BEX5Cuyk/5gFCUZ5F3i7Hnba6snZftWla7Gglwc5pIgcd+E7cW+rPg==", - "dev": true - }, - "node_modules/electron-window-state": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz", - "integrity": "sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg==", - "dependencies": { - "jsonfile": "^4.0.0", - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/electron-window-state/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron/node_modules/@types/node": { - "version": "16.11.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.64.tgz", - "integrity": "sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/error-stack-parser": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", - "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", - "dev": true, - "dependencies": { - "stackframe": "^1.1.1" - } - }, - "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true - }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz", - "integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.2.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dev": true, - "dependencies": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@babel/plugin-syntax-flow": "^7.14.5", - "@babel/plugin-transform-react-jsx": "^7.14.9", - "eslint": "^8.1.0" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "@typescript-eslint/eslint-plugin": { - "optional": true - }, - "jest": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", - "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.18.9", - "aria-query": "^4.2.2", - "array-includes": "^3.1.5", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.4.3", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.2", - "language-tags": "^1.0.5", - "minimatch": "^3.1.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-testing-library": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.7.2.tgz", - "integrity": "sha512-0ZmHeR/DUUgEzW8rwUBRWxuqntipDtpvxK0hymdHnLlABryJkzd+CAHr+XnISaVsTisZ5MLHp6nQF+8COHLLTA==", - "dev": true, - "dependencies": { - "@typescript-eslint/utils": "^5.13.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0", - "npm": ">=6" - }, - "peerDependencies": { - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", - "dev": true, - "dependencies": { - "@types/eslint": "^7.28.2", - "jest-worker": "^27.3.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "schema-utils": "^3.1.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", - "dev": true, - "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esri-leaflet": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/esri-leaflet/-/esri-leaflet-3.0.8.tgz", - "integrity": "sha512-mLb4pRfDAbkG1YhuajD22erLXIAtrF1R32hmgmlJNI3t47n6KjTppCb8lViia0O7+GDORXFuJ9Lj9RkpsaKhSA==", - "dependencies": { - "@terraformer/arcgis": "^2.1.0", - "tiny-binary-search": "^1.0.3" - }, - "peerDependencies": { - "leaflet": "^1.0.0" - } - }, - "node_modules/esri-leaflet-cluster": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/esri-leaflet-cluster/-/esri-leaflet-cluster-3.0.0.tgz", - "integrity": "sha512-aAj2Bv7Lv8e4uK/BLT5EJlIizk+28NSSYbkYcPT+HYrnmLwog01V7pGxGOmI3HMpDMTjlt8WE9DpygMy6TIwQQ==", - "peer": true, - "peerDependencies": { - "esri-leaflet": "*", - "leaflet": "*", - "leaflet.markercluster": "^1.0.0" - } - }, - "node_modules/esri-leaflet-geocoder": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esri-leaflet-geocoder/-/esri-leaflet-geocoder-3.1.3.tgz", - "integrity": "sha512-XuorBaPKOq2XBswyWS3fX4I0EyGamdQsao/NQbn+9wlCZtpDrpIn2iKLY7x4uOaPC4wCjE/rskli8UMCVwlZrg==", - "peer": true, - "dependencies": { - "esri-leaflet": "^3.0.2", - "leaflet": "^1.0.0" - } - }, - "node_modules/esri-leaflet-heatmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esri-leaflet-heatmap/-/esri-leaflet-heatmap-2.0.1.tgz", - "integrity": "sha512-Yd6gNghJfG5Zv7+5A0SraqIMK6nqYSAkF925DXnpbi5BFbI8vbJFK8JyG9hFq+vC/iBtCCpQyGz0UjtHMzNrPg==", - "peer": true, - "dependencies": { - "leaflet": "^1.0.0-rc.3", - "leaflet.heat": "^0.2.0" - }, - "peerDependencies": { - "esri-leaflet": ">2.3.0" - } - }, - "node_modules/esri-leaflet-vector": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/esri-leaflet-vector/-/esri-leaflet-vector-3.1.5.tgz", - "integrity": "sha512-XNRkrqfB4xKGQfRtjiMJsxwF4oiPnSNngQJrLBbMQMadLqcy+mZRAbDHDx/KEK6S0w0QoM4/A+A2rcNHHBQKlA==", - "peer": true, - "dependencies": { - "mapbox-gl": "1.13.1" - }, - "peerDependencies": { - "esri-leaflet": ">2.3.0", - "leaflet": "^1.5.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", - "dev": true, - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.19.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.7", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", - "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", - "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - }, - "peerDependencies": { - "eslint": ">= 6", - "typescript": ">= 2.7", - "vue-template-compiler": "*", - "webpack": ">= 4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - }, - "vue-template-compiler": { - "optional": true - } - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fraction.js": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.3.tgz", - "integrity": "sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generate-license-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-license-file/-/generate-license-file-2.0.0.tgz", - "integrity": "sha512-GutXlMEwS6cxXhd6G7FM6iyzGVnN23S0m3Z3GI6cabqrE4lb5Ebzx2nxW0bXyPYMsHjBBzbM6xx+ZLhe7CI7Xg==", - "dev": true, - "dependencies": { - "arg": "^5.0.0", - "cli-spinners": "^2.6.0", - "enquirer": "^2.3.6", - "esm": "^3.2.25", - "license-checker": "^25.0.1", - "ora": "^5.4.1" - }, - "bin": { - "generate-license-file": "bin/generate-license-file" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/geojson-vt": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", - "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", - "peer": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", - "peer": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "dependencies": { - "global-prefix": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "dependencies": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "optional": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "node_modules/graphql": { - "version": "16.7.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.7.1.tgz", - "integrity": "sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, - "node_modules/grid-index": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", - "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", - "peer": true - }, - "node_modules/gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/headers-polyfill": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", - "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==", - "dev": true - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", - "dev": true - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", - "dev": true, - "dependencies": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/html-webpack-plugin" - }, - "peerDependencies": { - "webpack": "^5.20.0" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http2-client": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", - "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", - "dev": true - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/idb": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", - "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==", - "dev": true - }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", - "dev": true, - "dependencies": { - "harmony-reflect": "^1.4.6" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "9.0.12", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", - "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/inquirer": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", - "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true - }, - "node_modules/ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", - "dev": true, - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jake/node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "node_modules/jake/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jake/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jake/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jake/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=", - "dev": true - }, - "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-circus/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-circus/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-circus/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-config/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-config/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-config/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-config/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-each/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-each/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-each/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-each/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-each/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-jasmine2/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-jasmine2/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-jasmine2/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dev": true, - "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-resolve/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-resolve/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-resolve/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-resolve/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-resolve/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runner/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runner/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runner/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runner/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runner/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-runtime/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-runtime/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-runtime/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-snapshot/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-transform-stub": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz", - "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==", - "dev": true - }, - "node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-validate/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-validate/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-validate/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.0.0.tgz", - "integrity": "sha512-jxoszalAb394WElmiJTFBMzie/RDCF+W7Q29n5LzOPtcoQoHWfdUtHFkbhgf5NwWe8uMOxvKb/g7ea7CshfkTw==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^27.0.0", - "jest-watcher": "^27.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "jest": "^27.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/char-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", - "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", - "dev": true, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watch-typeahead/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watch-typeahead/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watch-typeahead/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dev": true, - "dependencies": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/jest-watch-typeahead/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-watcher/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-watcher/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-watcher/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonpointer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.0.tgz", - "integrity": "sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/kdbush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", - "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", - "peer": true - }, - "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dev": true, - "dependencies": { - "language-subtag-registry": "~0.3.2" - } - }, - "node_modules/leaflet": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.2.tgz", - "integrity": "sha512-Kc77HQvWO+y9y2oIs3dn5h5sy2kr3j41ewdqCMEUA4N89lgfUUfOBy7wnnHEstDpefiGFObq12FdopGRMx4J7g==" - }, - "node_modules/leaflet-ruler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/leaflet-ruler/-/leaflet-ruler-1.0.0.tgz", - "integrity": "sha512-5Ti99czL+hhcd5rMmT5JBkDvzErPUM+ogJbP6NDzJEMK5vCGqS9/1BrMpVeCcCaxViSWLPf9qcXRGcGO85UCZA==", - "peerDependencies": { - "leaflet": "^1.0.0" - } - }, - "node_modules/leaflet.heat": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/leaflet.heat/-/leaflet.heat-0.2.0.tgz", - "integrity": "sha512-Cd5PbAA/rX3X3XKxfDoUGi9qp78FyhWYurFg3nsfhntcM/MCNK08pRkf4iEenO1KNqwVPKCmkyktjW3UD+h9bQ==", - "peer": true - }, - "node_modules/leaflet.markercluster": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", - "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", - "peer": true, - "peerDependencies": { - "leaflet": "^1.3.1" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "bin": { - "license-checker": "bin/license-checker" - } - }, - "node_modules/license-checker/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/license-checker/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mapbox-gl": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.1.tgz", - "integrity": "sha512-GSyubcoSF5MyaP8z+DasLu5v7KmDK2pp4S5+VQ5WdVQUOaAqQY4jwl4JpcdNho3uWm2bIKs7x1l7q3ynGmW60g==", - "peer": true, - "dependencies": { - "@mapbox/geojson-rewind": "^0.5.0", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.5.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.1", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.2", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.2.1", - "grid-index": "^1.1.0", - "minimist": "^1.2.5", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^7.1.0", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.1" - }, - "engines": { - "node": ">=6.4.0" - } - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/matcher/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", - "dev": true, - "dependencies": { - "fs-monkey": "1.0.3" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/milsymbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/milsymbol/-/milsymbol-2.0.0.tgz", - "integrity": "sha512-GcBFrcIUr8jScaZqZb0SI2W6AbnUrPCTHu2kqHxduQjN2DIN8q5pY6ksSWfnJ4HlcIAWQhyotbdPIr1bBxFbwQ==" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", - "integrity": "sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/msw": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/msw/-/msw-1.2.2.tgz", - "integrity": "sha512-GsW3PE/Es/a1tYThXcM8YHOZ1S1MtivcS3He/LQbbTCx3rbWJYCtWD5XXyJ53KlNPT7O1VI9sCW3xMtgFe8XpQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@mswjs/cookies": "^0.2.2", - "@mswjs/interceptors": "^0.17.5", - "@open-draft/until": "^1.0.3", - "@types/cookie": "^0.4.1", - "@types/js-levenshtein": "^1.1.1", - "chalk": "4.1.1", - "chokidar": "^3.4.2", - "cookie": "^0.4.2", - "graphql": "^15.0.0 || ^16.0.0", - "headers-polyfill": "^3.1.2", - "inquirer": "^8.2.0", - "is-node-process": "^1.2.0", - "js-levenshtein": "^1.1.6", - "node-fetch": "^2.6.7", - "outvariant": "^1.4.0", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.4.3", - "type-fest": "^2.19.0", - "yargs": "^17.3.1" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.4.x <= 5.1.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/msw/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/msw/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/msw/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/msw/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/msw/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/msw/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/msw/node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true - }, - "node_modules/msw/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/msw/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/msw/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/msw/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "node_modules/murmurhash-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", - "peer": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dev": true, - "dependencies": { - "http2-client": "^1.2.5" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/node-forge": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz", - "integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==", - "dev": true, - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node_modules/node-readfiles": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", - "dev": true, - "dependencies": { - "es6-promise": "^3.2.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "node_modules/oas-kit-common": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", - "dev": true, - "dependencies": { - "fast-safe-stringify": "^2.0.7" - } - }, - "node_modules/oas-linter": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", - "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", - "dev": true, - "dependencies": { - "@exodus/schemasafe": "^1.0.0-rc.2", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-resolver": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", - "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", - "dev": true, - "dependencies": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "resolve": "resolve.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-resolver/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/oas-resolver/node_modules/yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/oas-resolver/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/oas-schema-walker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", - "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", - "dev": true, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-validator": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", - "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", - "dev": true, - "dependencies": { - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.8", - "oas-linter": "^3.2.2", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "reftools": "^1.1.9", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.hasown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", - "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openapi-types": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.2.tgz", - "integrity": "sha512-GuTo7FyZjOIWVhIhQSWJVaws6A82sWIGyQogxxYBYKZ0NBdyP2CYSIgOwFfSB+UVoPExk/YzFpyYitHS8KVZtA==", - "dev": true, - "peer": true - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ora/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ora/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/outvariant": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", - "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==", - "dev": true - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "dependencies": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pbf": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", - "peer": true, - "dependencies": { - "ieee754": "^1.1.12", - "resolve-protobuf-schema": "^2.1.0" - }, - "bin": { - "pbf": "bin/pbf" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dev": true, - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/postcss": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.7.tgz", - "integrity": "sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A==", - "dev": true, - "dependencies": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz", - "integrity": "sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.2" - }, - "peerDependencies": { - "postcss": "^8.0.2" - } - }, - "node_modules/postcss-browser-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "browserslist": ">=4", - "postcss": ">=8" - } - }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/postcss-clamp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.0.0.tgz", - "integrity": "sha512-FsMmeBZtymFN7Jtlnw9is8I4nB+qEEb/qS0ZLTIqcKiwZyHBq44Yhv29Q+VQsTGHYFqIr/s/9tqvNM7j+j1d+g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=7.6.0" - }, - "peerDependencies": { - "postcss": "^8.4.6" - } - }, - "node_modules/postcss-color-functional-notation": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.2.tgz", - "integrity": "sha512-DXVtwUhIk4f49KK5EGuEdgx4Gnyj6+t2jBSEmxvpIK9QI40tWrpS2Pua8Q7iIZWBrki2QOaeUdEaLPPa91K0RQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.3.tgz", - "integrity": "sha512-fESawWJCrBV035DcbKRPAVmy21LpoyiXdPTuHUfWJ14ZRjY7Y7PA6P4g8z6LQGYhU1WAxkTxjIjurXzoe68Glw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-color-rebeccapurple": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz", - "integrity": "sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-colormin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.5.tgz", - "integrity": "sha512-+X30aDaGYq81mFqwyPpnYInsZQnNpdxMX0ajlY7AExCexEFkPVV+KrO7kXwayqEWL2xwEbNQ4nUO0ZsRWGnevg==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.4.tgz", - "integrity": "sha512-bugzSAyjIexdObovsPZu/sBCTHccImJxLyFgeV0MmNBm/Lw5h5XnjfML6gzEmJ3A6nyfCW7hb1JXzcsA4Zfbdw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-custom-media": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", - "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-custom-properties": { - "version": "12.1.4", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz", - "integrity": "sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-custom-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz", - "integrity": "sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.2" - } - }, - "node_modules/postcss-dir-pseudo-class": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.4.tgz", - "integrity": "sha512-I8epwGy5ftdzNWEYok9VjW9whC4xnelAtbajGv4adql4FIF09rnrxnA9Y8xSHN47y7gqFIv10C5+ImsLeJpKBw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-discard-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz", - "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz", - "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz", - "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz", - "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-double-position-gradients": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.0.tgz", - "integrity": "sha512-oz73I08yMN3oxjj0s8mED1rG+uOYoK3H8N9RjQofyg52KBRNmePJKg3fVwTpL2U5ZFbCzXoZBsUD/CvZdlqE4Q==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-env-function": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.5.tgz", - "integrity": "sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.4" - } - }, - "node_modules/postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-gap-properties": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", - "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-image-set-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.6.tgz", - "integrity": "sha512-KfdC6vg53GC+vPd2+HYzsZ6obmPqOk6HY09kttU19+Gj1nC3S3XBVEXDHxkhxTohgZqzbUb94bKXvKDnYWBm/A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.3.3" - } - }, - "node_modules/postcss-lab-function": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.1.tgz", - "integrity": "sha512-j3Z0WQCimY2tMle++YcmygnnVbt6XdnrCV1FO2IpzaCSmtTF2oO8h4ZYUA1Q+QHYroIiaWPvNHt9uBR4riCksQ==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-load-config": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.3.tgz", - "integrity": "sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw==", - "dev": true, - "dependencies": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" - }, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } - }, - "node_modules/postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.6.tgz", - "integrity": "sha512-rkmoPwQO6ymJSmWsX6l2hHeEBQa7C4kJb9jyi5fZB1sE8nSCv7sqchoYPixRwX/yvLoZP2y6FA5kcjiByeJqDg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.0.3" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.6.tgz", - "integrity": "sha512-nzJWJ9yXWp8AOEpn/HFAW72WKVGD2bsLiAmgw4hDchSij27bt6TF+sIK0cJUBAYT3SGcjtGGsOR89bwkkMuMgQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.2", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.4.tgz", - "integrity": "sha512-RN6q3tyuEesvyCYYFCRGJ41J1XFvgV+dvYGHr0CeHv8F00yILlN8Slf4t8XW4IghlfZYCeyRrANO6HpJ948ieA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.6.tgz", - "integrity": "sha512-E/dT6oVxB9nLGUTiY/rG5dX9taugv9cbLNTFad3dKxOO+BQg25Q/xo2z2ddG+ZB1CbkZYaVwx5blY8VC7R/43A==", - "dev": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.5.tgz", - "integrity": "sha512-YBNuq3Rz5LfLFNHb9wrvm6t859b8qIqfXsWeK7wROm3jSKNpO1Y5e8cOyBv6Acji15TgSrAwb3JkVNCqNyLvBg==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.3.tgz", - "integrity": "sha512-9RJfTiQEKA/kZhMaEXND893nBqmYQ8qYa/G+uPdVnXF6D/FzpfI6kwBtWEcHx5FqDbA79O9n6fQJfrIj6M8jvQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.6" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nesting": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.2.tgz", - "integrity": "sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.8" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-normalize": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", - "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", - "dev": true, - "dependencies": { - "@csstools/normalize.css": "*", - "postcss-browser-comments": "^4", - "sanitize.css": "*" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "browserslist": ">= 4", - "postcss": ">= 8" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz", - "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.3.tgz", - "integrity": "sha512-FIV5FY/qs4Ja32jiDb5mVj5iWBlS3N8tFcw2yg98+8MkRgyhtnBgSC0lxU+16AMHbjX5fbSJgw5AXLMolonuRQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.4.tgz", - "integrity": "sha512-qynirjBX0Lc73ROomZE3lzzmXXTu48/QiEzKgMeqh28+MfuHLsuqC9po4kj84igZqqFGovz8F8hf44hA3dPYmQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.4.tgz", - "integrity": "sha512-Innt+wctD7YpfeDR7r5Ik6krdyppyAg2HBRpX88fo5AYzC1Ut/l3xaxACG0KsbX49cO2n5EB13clPwuYVt8cMA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.4.tgz", - "integrity": "sha512-Dfk42l0+A1CDnVpgE606ENvdmksttLynEqTQf5FL3XGQOyqxjbo25+pglCUvziicTxjtI2NLUR6KkxyUWEVubQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.3.tgz", - "integrity": "sha512-QRfjvFh11moN4PYnJ7hia4uJXeFotyK3t2jjg8lM9mswleGsNw2Lm3I5wO+l4k1FzK96EFwEVn8X8Ojrp2gP4g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.4.tgz", - "integrity": "sha512-W79Regn+a+eXTzB+oV/8XJ33s3pDyFTND2yDuUCo0Xa3QSy1HtNIfRVPXNubHxjhlqmMFADr3FSCHT84ITW3ig==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.5.tgz", - "integrity": "sha512-Ws3tX+PcekYlXh+ycAt0wyzqGthkvVtZ9SZLutMVvHARxcpu4o7vvXcNoiNKyjKuWecnjS6HDI3fjBuDr5MQxQ==", - "dev": true, - "dependencies": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.4.tgz", - "integrity": "sha512-wsnuHolYZjMwWZJoTC9jeI2AcjA67v4UuidDrPN9RnX8KIZfE+r2Nd6XZRwHVwUiHmRvKQtxiqo64K+h8/imaw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-opacity-percentage": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", - "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", - "dev": true, - "funding": [ - { - "type": "kofi", - "url": "https://ko-fi.com/mrcgrtz" - }, - { - "type": "liberapay", - "url": "https://liberapay.com/mrcgrtz" - } - ], - "engines": { - "node": "^12 || ^14 || >=16" - } - }, - "node_modules/postcss-ordered-values": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.5.tgz", - "integrity": "sha512-mfY7lXpq+8bDEHfP+muqibDPhZ5eP9zgBEF9XRvoQgXcQe2Db3G1wcvjbnfjXG6wYsl+0UIjikqq4ym1V2jGMQ==", - "dev": true, - "dependencies": { - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-overflow-shorthand": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", - "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8" - } - }, - "node_modules/postcss-place": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.4.tgz", - "integrity": "sha512-MrgKeiiu5OC/TETQO45kV3npRjOFxEHthsqGtkh3I1rPbZSbXGD/lZVi9j13cYh+NA8PIAPyk6sGjT9QbRyvSg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-preset-env": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.4.1.tgz", - "integrity": "sha512-UvBVvPJ2vb4odAtckSbryndyBz+Me1q8wawqq0qznpDXy188I+8W5Sa929sCPqw2/NSYnqpHJbo41BKso3+I9A==", - "dev": true, - "dependencies": { - "@csstools/postcss-color-function": "^1.0.2", - "@csstools/postcss-font-format-keywords": "^1.0.0", - "@csstools/postcss-hwb-function": "^1.0.0", - "@csstools/postcss-ic-unit": "^1.0.0", - "@csstools/postcss-is-pseudo-class": "^2.0.0", - "@csstools/postcss-normalize-display-values": "^1.0.0", - "@csstools/postcss-oklab-function": "^1.0.1", - "@csstools/postcss-progressive-custom-properties": "^1.2.0", - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "css-blank-pseudo": "^3.0.3", - "css-has-pseudo": "^3.0.4", - "css-prefers-color-scheme": "^6.0.3", - "cssdb": "^6.3.1", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-clamp": "^4.0.0", - "postcss-color-functional-notation": "^4.2.2", - "postcss-color-hex-alpha": "^8.0.3", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.4", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.4", - "postcss-double-position-gradients": "^3.1.0", - "postcss-env-function": "^4.0.5", - "postcss-focus-visible": "^6.0.4", - "postcss-focus-within": "^5.0.4", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.3", - "postcss-image-set-function": "^4.0.6", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.1.1", - "postcss-logical": "^5.0.4", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-opacity-percentage": "^1.1.2", - "postcss-overflow-shorthand": "^3.0.3", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.4", - "postcss-pseudo-class-any-link": "^7.1.1", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.1.tgz", - "integrity": "sha512-JRoLFvPEX/1YTPxRxp1JO4WxBVXJYrSY7NHeak5LImwJ+VobFMwYDQHvfTXEpcn+7fYIeGkC29zYFhFWIZD8fg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.3.tgz", - "integrity": "sha512-c88TkSnQ/Dnwgb4OZbKPOBbCaauwEjbECP5uAuFPOzQ+XdjNjRH7SG0dteXrpp1LlIFEKK76iUGgmw2V0xeieA==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.4.tgz", - "integrity": "sha512-VIJB9SFSaL8B/B7AXb7KHL6/GNNbbCHslgdzS9UDfBZYIA2nx8NLY7iD/BXFSO/1sRUILzBTfHCoW5inP37C5g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.3" - } - }, - "node_modules/postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.4.tgz", - "integrity": "sha512-yDKHvULbnZtIrRqhZoA+rxreWpee28JSRH/gy9727u0UCgtpv1M/9WEWY3xySlFa0zQJcqf6oCBJPR5NwkmYpg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-svgo/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/postcss-svgo/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/postcss-svgo/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "node_modules/postcss-svgo/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-svgo/node_modules/svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.4.tgz", - "integrity": "sha512-5ampwoSDJCxDPoANBIlMgoBcYUHnhaiuLYJR5pj1DLnYQvMRVyFuTA5C3Bvt+aHtiqWpJkD/lXT50Vo1D0ZsAQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "peer": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - }, - "node_modules/protocol-buffers-schema": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", - "peer": true - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "dev": true, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", - "peer": true - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", - "dev": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", - "dev": true, - "dependencies": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/react-dev-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/react-dev-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/react-dev-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/react-dev-utils/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/react-dev-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", - "dev": true - }, - "node_modules/react-esri-leaflet": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/react-esri-leaflet/-/react-esri-leaflet-2.0.1.tgz", - "integrity": "sha512-5keSefL7gfEIK+QTfxJ/sZ+Fve8zk9zfT1QeAiFroY8p+qBfW6G1vvJ4Nz/+LDwk3AjSszzK3SBfCiE6QUftRg==", - "dependencies": { - "@react-leaflet/core": "^2.0.0" - }, - "peerDependencies": { - "esri-leaflet": "^3.0.8", - "esri-leaflet-cluster": "^3.0.0", - "esri-leaflet-geocoder": "^3.1.3", - "esri-leaflet-heatmap": "^2.0.1", - "esri-leaflet-vector": "^3.1.2", - "leaflet": "^1.8.0", - "leaflet.heat": "^0.2.0", - "leaflet.markercluster": "^1.5.3", - "react": "^18.0.0", - "react-dom": "^18.0.0", - "react-leaflet": "^4.0.0" - } - }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "node_modules/react-leaflet": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.1.0.tgz", - "integrity": "sha512-i+V9pX5lywJ48O2+K3USeeTdYLIhxnLMweH+YLd/UPqVIj3uKzE3Q29bzt83PBtViyZmxDlulzC6uoR3JLiE9A==", - "dependencies": { - "@react-leaflet/core": "^2.1.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/react-redux": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.4.tgz", - "integrity": "sha512-yMfQ7mX6bWuicz2fids6cR1YT59VTuT8MKyyE310wJQlINKENCeT1UcPdEiX6znI5tF8zXyJ/VYvDgeGuaaNwQ==", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dev": true, - "dependencies": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - }, - "peerDependencies": { - "react": ">= 16", - "typescript": "^3.2.1 || ^4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.2" - } - }, - "node_modules/read-installed/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "dev": true, - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/redux": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", - "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/redux-logger": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", - "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=", - "dependencies": { - "deep-diff": "^0.3.5" - } - }, - "node_modules/redux-thunk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "peerDependencies": { - "redux": "^4" - } - }, - "node_modules/reftools": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", - "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", - "dev": true, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "node_modules/reselect": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", - "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-protobuf-schema": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "peer": true, - "dependencies": { - "protocol-buffers-schema": "^3.3.1" - } - }, - "node_modules/resolve-url-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", - "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", - "dev": true, - "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^7.0.35", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=8.9" - }, - "peerDependencies": { - "rework": "1.0.1", - "rework-visit": "1.0.0" - }, - "peerDependenciesMeta": { - "rework": { - "optional": true - }, - "rework-visit": { - "optional": true - } - } - }, - "node_modules/resolve-url-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "node_modules/resolve-url-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/roarr/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "optional": true - }, - "node_modules/rollup": { - "version": "2.68.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.68.0.tgz", - "integrity": "sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-terser/node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/rollup-plugin-terser/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "peer": true - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/sanitize.css": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", - "dev": true - }, - "node_modules/sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", - "dev": true, - "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } - } - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "node_modules/selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", - "dev": true, - "dependencies": { - "node-forge": "^1.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, - "optional": true - }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-error/node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dev": true, - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "node_modules/should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "dependencies": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "node_modules/should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "dependencies": { - "should-type": "^1.4.0" - } - }, - "node_modules/should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", - "dev": true, - "dependencies": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "node_modules/should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", - "dev": true - }, - "node_modules/should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "node_modules/should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "engines": { - "node": ">=8" - } - }, - "node_modules/slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true - }, - "node_modules/spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "dev": true, - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/stackframe": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", - "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==", - "dev": true - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/strict-event-emitter": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", - "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", - "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.1", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-loader": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/stylehacks": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.3.tgz", - "integrity": "sha512-ENcUdpf4yO0E1rubu8rkxI+JGQk4CgjchynZ4bDBJDfqdy+uhTRSWb8/F3Jtu+Bw5MW45Po3/aQGeIyyxgQtxg==", - "dev": true, - "dependencies": { - "browserslist": "^4.16.6", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >=14.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/supercluster": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", - "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", - "peer": true, - "dependencies": { - "kdbush": "^3.0.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true - }, - "node_modules/svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/svgo/node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "node_modules/svgo/node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/swagger2openapi": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", - "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", - "dev": true, - "dependencies": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "bin": { - "boast": "boast.js", - "oas-validate": "oas-validate.js", - "swagger2openapi": "swagger2openapi.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/swagger2openapi/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/swagger2openapi/node_modules/yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/swagger2openapi/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/tailwindcss": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz", - "integrity": "sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==", - "dev": true, - "dependencies": { - "arg": "^5.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "cosmiconfig": "^7.0.1", - "detective": "^5.2.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss": "^8.4.6", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - }, - "peerDependencies": { - "autoprefixer": "^10.0.2", - "postcss": "^8.0.9" - } - }, - "node_modules/tailwindcss/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/tailwindcss/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/tailwindcss/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/tailwindcss/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/tailwindcss/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tailwindcss/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "dependencies": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tempy/node_modules/type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "dependencies": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "node_modules/tiny-binary-search": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-binary-search/-/tiny-binary-search-1.0.3.tgz", - "integrity": "sha512-STSHX/L5nI9WTLv6wrzJbAPbO7OIISX83KFBh2GVbX1Uz/vgZOU/ANn/8iV6t35yMTpoPzzO+3OQid3mifE0CA==" - }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "peer": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tsconfig-paths/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", - "dev": true - }, - "node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", - "peer": true, - "dependencies": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "dev": true, - "dependencies": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/wait-on/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "dependencies": { - "follow-redirects": "^1.14.7" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "dev": true, - "dependencies": { - "util": "^0.12.3" - }, - "optionalDependencies": { - "@zxing/text-encoding": "0.9.0" - } - }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", - "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", - "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.1", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz", - "integrity": "sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A==", - "dev": true, - "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 12.13.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dev": true, - "dependencies": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "peerDependencies": { - "webpack": "^4.44.2 || ^5.47.0" - } - }, - "node_modules/webpack-manifest-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-manifest-plugin/node_modules/webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", - "dev": true - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workbox-background-sync": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.5.0.tgz", - "integrity": "sha512-rrekt/gt6qOIZsisj6QZfmAFPAnocq1Z603zAjt+qHmeXY8DLPOklVtvrXSaHoHH3qIjUq3SQY5s2x240iTIKw==", - "dev": true, - "dependencies": { - "idb": "^6.1.4", - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-broadcast-update": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.5.0.tgz", - "integrity": "sha512-JC97c7tYqoGWcCfbKO9KHG6lkU+WhXCnDB2j1oFWEiv53nUHy3yjPpzMmAGNLD9oV5lInO15n6V18HfwgkhISw==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-build": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.5.0.tgz", - "integrity": "sha512-da0/1b6//P9+ts7ofcIKcMVPyN6suJvjJASXokF7DsqvUmgRBPcCVV4KCy8QWjgfcz7mzuTpkSbdVHcPFJ/p0A==", - "dev": true, - "dependencies": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.5.0", - "workbox-broadcast-update": "6.5.0", - "workbox-cacheable-response": "6.5.0", - "workbox-core": "6.5.0", - "workbox-expiration": "6.5.0", - "workbox-google-analytics": "6.5.0", - "workbox-navigation-preload": "6.5.0", - "workbox-precaching": "6.5.0", - "workbox-range-requests": "6.5.0", - "workbox-recipes": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0", - "workbox-streams": "6.5.0", - "workbox-sw": "6.5.0", - "workbox-window": "6.5.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.3.tgz", - "integrity": "sha512-9o+HO2MbJhJHjDYZaDxJmSDckvDpiuItEsrIShV0DXeCshXWRHhqYyU/PKHMkuClOmFnZhRd6wzv4vpDu/dRKg==", - "dev": true, - "dependencies": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "ajv": ">=8" - } - }, - "node_modules/workbox-build/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/workbox-build/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/workbox-build/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/workbox-build/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workbox-build/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/workbox-build/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/workbox-build/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.5.0.tgz", - "integrity": "sha512-sqAtWAiBwWvI8HG/2Do7BeKPhHuUczt22ORkAjkH9DfTq9LuWRFd6T4HAMqX5G8F1gM9XA2UPlxRrEeSpFIz/A==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-core": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.0.tgz", - "integrity": "sha512-5SPwNipUzYBhrneLVT02JFA0fw3LG82jFAN/G2NzxkIW10t4MVZuML2nU94bbkgjq25u0fkY8+4JXzMfHgxEWQ==", - "dev": true - }, - "node_modules/workbox-expiration": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.5.0.tgz", - "integrity": "sha512-y3WRkKRy/gMuZZNkrLFahjY0QZtLoq+QfhTbVAsOGHVg1CCtnNbeFAnEidQs7UisI2BK76VqQPvM7hEOFyZ92A==", - "dev": true, - "dependencies": { - "idb": "^6.1.4", - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-google-analytics": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.5.0.tgz", - "integrity": "sha512-CHHh55wMNCc/BV1URrzEM2Zjgf6g2CV6QpAAc1pBRqaLY5755PeQZbp3o8KbJEM7YsC9mIBeQVsOkSKkGS30bg==", - "dev": true, - "dependencies": { - "workbox-background-sync": "6.5.0", - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.5.0.tgz", - "integrity": "sha512-ktrRQzXJ0zFy0puOtCa49wE3BSBGUB8KRMot3tEieikCkSO0wMLmiCb9GwTVvNMJLl0THRlsdFoI93si04nTxA==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-precaching": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.5.0.tgz", - "integrity": "sha512-IVLzgHx38T6LphJyEOltd7XAvpDi73p85uCT2ZtT1HHg9FAYC49a+5iHUVOnqye73fLW20eiAMFcnehGxz9RWg==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "node_modules/workbox-range-requests": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.5.0.tgz", - "integrity": "sha512-+qTELdGZE5rOjuv+ifFrfRDN8Uvzpbm5Fal7qSUqB1V1DLCMxPwHCj6mWwQBRKBpW7G09kAwewH7zA3Asjkf/Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-recipes": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.5.0.tgz", - "integrity": "sha512-7hWZAIcXmvr31NwYSWaQIrnThCH/Dx9+eYv/YdkpUeWIXRiHRkYvP1FdiHItbLSjL4Y6K7cy2Y9y5lGCkgaE4w==", - "dev": true, - "dependencies": { - "workbox-cacheable-response": "6.5.0", - "workbox-core": "6.5.0", - "workbox-expiration": "6.5.0", - "workbox-precaching": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "node_modules/workbox-routing": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.0.tgz", - "integrity": "sha512-w1A9OVa/yYStu9ds0Dj+TC6zOAoskKlczf+wZI5mrM9nFCt/KOMQiFp1/41DMFPrrN/8KlZTS3Cel/Ttutw93Q==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-strategies": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.0.tgz", - "integrity": "sha512-Ngnwo+tfGw4uKSlTz3h1fYKb/lCV7SDI/dtTb8VaJzRl0N9XssloDGYERBmF6BN/DV/x3bnRsshfobnKI/3z0g==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0" - } - }, - "node_modules/workbox-streams": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.5.0.tgz", - "integrity": "sha512-ZbeaZINkju4x45P9DFyRbOYInE+dyNAJIelflz4f9AOAdm+zZUJCooU4MdfsedVhHiTIA6pCD/3jCmW1XbvlbA==", - "dev": true, - "dependencies": { - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0" - } - }, - "node_modules/workbox-sw": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.0.tgz", - "integrity": "sha512-uPGJ9Yost4yabnCko/IuhouquoQKrWOEqLq7L/xVYtltWe4+J8Hw8iPCVtxvXQ26hffd7MaFWUAN83j2ZWbxRg==", - "dev": true - }, - "node_modules/workbox-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-wy4uCBJELNfJVf2b4Tg3mjJQySq/aReWv4Q1RxQweJkY9ihq7DOGA3wLlXvoauek+MX/SuQfS3it+eXIfHKjvg==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.5.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "webpack": "^4.4.0 || ^5.9.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/workbox-webpack-plugin/node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/workbox-window": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.0.tgz", - "integrity": "sha512-DOrhiTnWup/CsNstO2uvfdKM4kdStgHd31xGGvBcoCE3Are3DRcy5s3zz3PedcAR1AKskQj3BXz0UhzQiOq8nA==", - "dev": true, - "dependencies": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.5.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==" - }, - "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.0" - } - }, - "@apidevtools/json-schema-ref-parser": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz", - "integrity": "sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==", - "dev": true, - "requires": { - "@jsdevtools/ono": "^7.1.3", - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.13.1" - } - }, - "@apidevtools/openapi-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", - "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==", - "dev": true - }, - "@apidevtools/swagger-methods": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", - "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==", - "dev": true - }, - "@apidevtools/swagger-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz", - "integrity": "sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==", - "dev": true, - "requires": { - "@apidevtools/json-schema-ref-parser": "9.0.6", - "@apidevtools/openapi-schemas": "^2.1.0", - "@apidevtools/swagger-methods": "^3.0.2", - "@jsdevtools/ono": "^7.1.3", - "ajv": "^8.6.3", - "ajv-draft-04": "^1.0.0", - "call-me-maybe": "^1.0.1" - }, - "dependencies": { - "ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, - "requires": {} - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", - "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" - } - }, - "@babel/compat-data": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.3.tgz", - "integrity": "sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==", - "dev": true - }, - "@babel/core": { - "version": "7.17.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.8.tgz", - "integrity": "sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.7", - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-module-transforms": "^7.17.7", - "@babel/helpers": "^7.17.8", - "@babel/parser": "^7.17.8", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/eslint-parser": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", - "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", - "dev": true, - "requires": { - "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", - "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz", - "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", - "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.19.3", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", - "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.9", - "@babel/helper-split-export-declaration": "^7.18.6" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "dev": true - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dev": true, - "requires": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", - "dev": true, - "requires": { - "@babel/types": "^7.18.9" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-module-transforms": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", - "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-member-expression-to-functions": "^7.18.9", - "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.19.1", - "@babel/types": "^7.19.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "requires": { - "@babel/types": "^7.22.5" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" - }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helpers": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.0.tgz", - "integrity": "sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==", - "dev": true, - "requires": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.19.0", - "@babel/types": "^7.19.0" - }, - "dependencies": { - "@babel/types": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.3.tgz", - "integrity": "sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", - "requires": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", - "dev": true - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz", - "integrity": "sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.6", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-decorators": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz", - "integrity": "sha512-MbgXtNXqo7RTKYIXVchVJGPvaVufQH3pxvQyfbGvNw1DObIhph+PesYXJTcd8J4DdWibvf6Z2eanOyItX8WnJg==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/helper-replace-supers": "^7.19.1", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/plugin-syntax-decorators": "^7.19.0" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz", - "integrity": "sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.0", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-decorators": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz", - "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", - "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz", - "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-flow": "^7.18.6" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.17.6.tgz", - "integrity": "sha512-OBv9VkyyKtsHZiHLoSfCn+h6yU7YKX8nrs32xUmOa1SRSk+t03FosB6fBZ0Yz4BpD1WV7l73Nsad+2Tz7APpqw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz", - "integrity": "sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.17.0" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "dev": true, - "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dev": true, - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz", - "integrity": "sha512-2nJjTUFIzBMP/f/miLxEK9vxwW/KUXsdvN4sR//TmuDhe6yU2h57WmIOE12Gng3MDP/xpjUV/ToZRdcf8Yj4fA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.19.0", - "babel-plugin-polyfill-corejs2": "^0.3.3", - "babel-plugin-polyfill-corejs3": "^0.6.0", - "babel-plugin-polyfill-regenerator": "^0.4.1", - "semver": "^6.3.0" - }, - "dependencies": { - "babel-plugin-polyfill-corejs3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3", - "core-js-compat": "^3.25.1" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.3" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typescript": { - "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.3.tgz", - "integrity": "sha512-z6fnuK9ve9u/0X0rRvI9MY0xg+DOUaABDYOe+/SQTxtlptaBB/V9JIUxJn6xp3lMBeb9qe8xSFmHU35oZDXD+w==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.19.0", - "@babel/helper-plugin-utils": "^7.19.0", - "@babel/plugin-syntax-typescript": "^7.18.6" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - } - }, - "@babel/preset-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz", - "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "@babel/plugin-transform-typescript": "^7.18.6" - } - }, - "@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/runtime-corejs3": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", - "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", - "dev": true, - "requires": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "dependencies": { - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", - "dev": true, - "requires": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - } - } - }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } - } - }, - "@csstools/normalize.css": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", - "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==", - "dev": true - }, - "@csstools/postcss-color-function": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.0.2.tgz", - "integrity": "sha512-uayvFqfa0hITPwVduxRYNL9YBD/anTqula0tu2llalaxblEd7QPuETSN3gB5PvTYxSfd0d8kS4Fypgo5JaUJ6A==", - "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-font-format-keywords": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.0.tgz", - "integrity": "sha512-oO0cZt8do8FdVBX8INftvIA4lUrKUSCcWUf9IwH9IPWOgKT22oAZFXeHLoDK7nhB2SmkNycp5brxfNMRLIhd6Q==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-hwb-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.0.tgz", - "integrity": "sha512-VSTd7hGjmde4rTj1rR30sokY3ONJph1reCBTUXqeW1fKwETPy1x4t/XIeaaqbMbC5Xg4SM/lyXZ2S8NELT2TaA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-ic-unit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.0.tgz", - "integrity": "sha512-i4yps1mBp2ijrx7E96RXrQXQQHm6F4ym1TOD0D69/sjDjZvQ22tqiEvaNw7pFZTUO5b9vWRHzbHzP9+UKuw+bA==", - "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-is-pseudo-class": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.0.tgz", - "integrity": "sha512-WnfZlyuh/CW4oS530HBbrKq0G8BKl/bsNr5NMFoubBFzJfvFRGJhplCgIJYWUidLuL3WJ/zhMtDIyNFTqhx63Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "@csstools/postcss-normalize-display-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.0.tgz", - "integrity": "sha512-bX+nx5V8XTJEmGtpWTO6kywdS725t71YSLlxWt78XoHUbELWgoCXeOFymRJmL3SU1TLlKSIi7v52EWqe60vJTQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-oklab-function": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.0.1.tgz", - "integrity": "sha512-Bnly2FWWSTZX20hDJLYHpurhp1ot+ZGvojLOsrHa9frzOVruOv4oPYMZ6wQomi9KsbZZ+Af/CuRYaGReTyGtEg==", - "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "@csstools/postcss-progressive-custom-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.2.0.tgz", - "integrity": "sha512-YLpFPK5OaLIRKZhUfnrZPT9s9cmtqltIOg7W6jPcxmiDpnZ4lk+odfufZttOAgcg6IHWvNLgcITSLpJxIQB/qQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "global-agent": "^3.0.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "dependencies": { - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - } - } - }, - "@eslint/eslintrc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.0.tgz", - "integrity": "sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.3.1", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@exodus/schemasafe": { - "version": "1.0.0-rc.7", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.7.tgz", - "integrity": "sha512-+1mBLsa+vvlV0lwEAP1hwgmOPkjMnoJ8hyCMfCCJga0sVDwDzrPJjnxZwdDaUmOh/vbFHQGBTk+FxsVjoI/CjQ==", - "dev": true - }, - "@hapi/hoek": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz", - "integrity": "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw==", - "dev": true - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", - "micromatch": "^4.0.4", - "rimraf": "^3.0.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/expect-utils": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.1.2.tgz", - "integrity": "sha512-4a48bhKfGj/KAH39u0ppzNTABXQ8QPccWAFUFobWBaEMSMp+sB31Z2fK/l47c4a/Mu1po2ffmfAIPxXbVTXdtg==", - "requires": { - "jest-get-type": "^29.0.0" - }, - "dependencies": { - "jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==" - } - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" - } - }, - "@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "slash": "^3.0.0", - "source-map": "^0.6.0", - "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/schemas": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", - "requires": { - "@sinclair/typebox": "^0.24.1" - } - }, - "@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", - "dev": true, - "requires": { - "@jest/test-result": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" - } - }, - "@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@jsdevtools/ono": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", - "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", - "dev": true - }, - "@mapbox/geojson-rewind": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-rewind/-/geojson-rewind-0.5.2.tgz", - "integrity": "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==", - "peer": true, - "requires": { - "get-stream": "^6.0.1", - "minimist": "^1.2.6" - } - }, - "@mapbox/geojson-types": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/geojson-types/-/geojson-types-1.0.2.tgz", - "integrity": "sha512-e9EBqHHv3EORHrSfbR9DqecPNn+AmuAoQxV6aL8Xu30bJMJR1o8PZLZzpk1Wq7/NfCbuhmakHTPYRhoqLsXRnw==", - "peer": true - }, - "@mapbox/jsonlint-lines-primitives": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", - "peer": true - }, - "@mapbox/mapbox-gl-supported": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-supported/-/mapbox-gl-supported-1.5.0.tgz", - "integrity": "sha512-/PT1P6DNf7vjEEiPkVIRJkvibbqWtqnyGaBz3nfRdcxclNSnSdaLU5tfAgcD7I8Yt5i+L19s406YLl1koLnLbg==", - "peer": true, - "requires": {} - }, - "@mapbox/point-geometry": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==", - "peer": true - }, - "@mapbox/tiny-sdf": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-1.2.5.tgz", - "integrity": "sha512-cD8A/zJlm6fdJOk6DqPUV8mcpyJkRz2x2R+/fYcWDYG3oWbG7/L7Yl/WqQ1VZCjnL9OTIMAn6c+BC5Eru4sQEw==", - "peer": true - }, - "@mapbox/unitbezier": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==", - "peer": true - }, - "@mapbox/vector-tile": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", - "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", - "peer": true, - "requires": { - "@mapbox/point-geometry": "~0.1.0" - } - }, - "@mapbox/whoots-js": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", - "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==", - "peer": true - }, - "@mswjs/cookies": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-0.2.2.tgz", - "integrity": "sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==", - "dev": true, - "requires": { - "@types/set-cookie-parser": "^2.4.0", - "set-cookie-parser": "^2.4.6" - } - }, - "@mswjs/interceptors": { - "version": "0.17.9", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.17.9.tgz", - "integrity": "sha512-4LVGt03RobMH/7ZrbHqRxQrS9cc2uh+iNKSj8UWr8M26A2i793ju+csaB5zaqYltqJmA2jUq4VeYfKmVqvsXQg==", - "dev": true, - "requires": { - "@open-draft/until": "^1.0.3", - "@types/debug": "^4.1.7", - "@xmldom/xmldom": "^0.8.3", - "debug": "^4.3.3", - "headers-polyfill": "^3.1.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.2.4", - "web-encoding": "^1.1.5" - }, - "dependencies": { - "strict-event-emitter": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.2.8.tgz", - "integrity": "sha512-KDf/ujU8Zud3YaLtMCcTI4xkZlZVIYxTLr+XIULexP+77EEVWixeXroLUXQXiVtH4XH2W7jr/3PT1v3zBuvc3A==", - "dev": true, - "requires": { - "events": "^3.3.0" - } - } - } - }, - "@nicolo-ribaudo/eslint-scope-5-internals": { - "version": "5.1.1-v1", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", - "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", - "dev": true, - "requires": { - "eslint-scope": "5.1.1" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@open-draft/until": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz", - "integrity": "sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==", - "dev": true - }, - "@pmmmwh/react-refresh-webpack-plugin": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz", - "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==", - "dev": true, - "requires": { - "ansi-html-community": "^0.0.8", - "common-path-prefix": "^3.0.0", - "core-js-pure": "^3.8.1", - "error-stack-parser": "^2.0.6", - "find-up": "^5.0.0", - "html-entities": "^2.1.0", - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", - "requires": {} - }, - "@reduxjs/toolkit": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.8.5.tgz", - "integrity": "sha512-f4D5EXO7A7Xq35T0zRbWq5kJQyXzzscnHKmjnu2+37B3rwHU6mX9PYlbfXdnxcY6P/7zfmjhgan0Z+yuOfeBmA==", - "requires": { - "immer": "^9.0.7", - "redux": "^4.1.2", - "redux-thunk": "^2.4.1", - "reselect": "^4.1.5" - } - }, - "@rollup/plugin-babel": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", - "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.10.4", - "@rollup/pluginutils": "^3.1.0" - } - }, - "@rollup/plugin-node-resolve": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", - "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.19.0" - } - }, - "@rollup/plugin-replace": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", - "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "magic-string": "^0.25.7" - } - }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, - "dependencies": { - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - } - } - }, - "@rtk-query/codegen-openapi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@rtk-query/codegen-openapi/-/codegen-openapi-1.0.0.tgz", - "integrity": "sha512-mptXwJVtMLozWFSqxm7WKY6K8duWLsPgjmkGjqaEqo5qEWJlARur6SHoqugKh3fHSM7vPaCS3VcWJ5RCYjup9Q==", - "dev": true, - "requires": { - "@apidevtools/swagger-parser": "^10.0.2", - "@rtk-query/oazapfts-patched": "^3.6.0-2", - "commander": "^6.2.0", - "prettier": "^2.2.1", - "semver": "^7.3.5", - "swagger2openapi": "^7.0.4", - "typescript": ">=4.1 <=4.5" - }, - "dependencies": { - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", - "dev": true - } - } - }, - "@rtk-query/oazapfts-patched": { - "version": "3.6.0-2", - "resolved": "https://registry.npmjs.org/@rtk-query/oazapfts-patched/-/oazapfts-patched-3.6.0-2.tgz", - "integrity": "sha512-9Y9j8BOvmb7WStrY2SomAk8syoAc8/8/EDS8OybG7G2mxy5aWH9qxNZgGxx9ODR4lQwbglan4+kTq0X6KqHUYA==", - "dev": true, - "requires": { - "@apidevtools/swagger-parser": "^10.0.1", - "lodash": "^4.17.20", - "minimist": "^1.2.5", - "swagger2openapi": "^7.0.7", - "typescript": "^4.1.2" - } - }, - "@rushstack/eslint-patch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", - "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", - "dev": true - }, - "@sideway/address": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz", - "integrity": "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "dev": true - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "dev": true - }, - "@sinclair/typebox": { - "version": "0.24.44", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.44.tgz", - "integrity": "sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg==" - }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@surma/rollup-plugin-off-main-thread": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", - "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", - "dev": true, - "requires": { - "ejs": "^3.1.6", - "json5": "^2.2.0", - "magic-string": "^0.25.0", - "string.prototype.matchall": "^4.0.6" - } - }, - "@svgr/babel-plugin-add-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", - "dev": true - }, - "@svgr/babel-plugin-remove-jsx-attribute": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", - "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", - "dev": true - }, - "@svgr/babel-plugin-remove-jsx-empty-expression": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", - "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", - "dev": true - }, - "@svgr/babel-plugin-replace-jsx-attribute-value": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", - "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", - "dev": true - }, - "@svgr/babel-plugin-svg-dynamic-title": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", - "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", - "dev": true - }, - "@svgr/babel-plugin-svg-em-dimensions": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", - "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", - "dev": true - }, - "@svgr/babel-plugin-transform-react-native-svg": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", - "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", - "dev": true - }, - "@svgr/babel-plugin-transform-svg-component": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", - "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", - "dev": true - }, - "@svgr/babel-preset": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", - "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", - "dev": true, - "requires": { - "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", - "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", - "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", - "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", - "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", - "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", - "@svgr/babel-plugin-transform-svg-component": "^5.5.0" - } - }, - "@svgr/core": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", - "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", - "dev": true, - "requires": { - "@svgr/plugin-jsx": "^5.5.0", - "camelcase": "^6.2.0", - "cosmiconfig": "^7.0.0" - } - }, - "@svgr/hast-util-to-babel-ast": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", - "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", - "dev": true, - "requires": { - "@babel/types": "^7.12.6" - } - }, - "@svgr/plugin-jsx": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", - "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@svgr/babel-preset": "^5.5.0", - "@svgr/hast-util-to-babel-ast": "^5.5.0", - "svg-parser": "^2.0.2" - } - }, - "@svgr/plugin-svgo": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", - "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", - "dev": true, - "requires": { - "cosmiconfig": "^7.0.0", - "deepmerge": "^4.2.2", - "svgo": "^1.2.2" - } - }, - "@svgr/webpack": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", - "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/plugin-transform-react-constant-elements": "^7.12.1", - "@babel/preset-env": "^7.12.1", - "@babel/preset-react": "^7.12.5", - "@svgr/core": "^5.5.0", - "@svgr/plugin-jsx": "^5.5.0", - "@svgr/plugin-svgo": "^5.5.0", - "loader-utils": "^2.0.0" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@terraformer/arcgis": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@terraformer/arcgis/-/arcgis-2.1.0.tgz", - "integrity": "sha512-eKTvNXze2Fo7vAEjvJFIGn5QdU0OP4aD9DuT/uTBLRM1QS+ju7KtPITbVW+xgCviHLnOVeFQ1UsIs9kjkakD4g==", - "requires": { - "@terraformer/common": "^2.0.7" - } - }, - "@terraformer/common": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@terraformer/common/-/common-2.0.7.tgz", - "integrity": "sha512-8bl+/JT0Rw6FYe2H3FfJS8uQwgzGl+UHs+8JX0TQLHgA4sMDEwObbMwo0iP3FVONwPXrPHEpC5YH7Grve0cl9A==" - }, - "@testing-library/dom": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.3.tgz", - "integrity": "sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==", - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^4.2.0", - "aria-query": "^5.0.0", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.4.4", - "pretty-format": "^27.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==" - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@testing-library/jest-dom": { - "version": "5.16.5", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz", - "integrity": "sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==", - "requires": { - "@adobe/css-tools": "^4.0.1", - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "aria-query": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz", - "integrity": "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg==" - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@testing-library/react": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-13.4.0.tgz", - "integrity": "sha512-sXOGON+WNTh3MLE9rve97ftaZukN3oNf2KjDy7YTx6hcTO2uuLHuCGynMDhFwGw/jYf4OJ2Qk0i4i79qMNNkyw==", - "requires": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.5.0", - "@types/react-dom": "^18.0.0" - } - }, - "@testing-library/user-event": { - "version": "14.4.3", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz", - "integrity": "sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==", - "requires": {} - }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@trivago/prettier-plugin-sort-imports": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz", - "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==", - "dev": true, - "requires": { - "@babel/generator": "7.17.7", - "@babel/parser": "^7.20.5", - "@babel/traverse": "7.23.2", - "@babel/types": "7.17.0", - "javascript-natural-sort": "0.7.1", - "lodash": "^4.17.21" - } - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true - }, - "@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "@types/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" - }, - "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bonjour": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", - "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/connect-history-api-fallback": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", - "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" - } - }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "@types/debug": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.8.tgz", - "integrity": "sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, - "@types/eslint": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", - "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/geojson": { - "version": "7946.0.8", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/hoist-non-react-statics": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", - "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", - "requires": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "@types/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", - "dev": true - }, - "@types/http-cache-semantics": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", - "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", - "dev": true - }, - "@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.1.2.tgz", - "integrity": "sha512-DcXGtoTykQB5jiwCmVr8H4vdg2OJhQex3qPkG+ISyDO7xQXbt/4R6dowcRyPemRnkH7JoHvZuxPBdlq+9JxFCg==", - "requires": { - "@jest/schemas": "^29.0.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", - "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", - "requires": { - "@types/yargs-parser": "*" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "diff-sequences": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.0.0.tgz", - "integrity": "sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==" - }, - "expect": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.1.2.tgz", - "integrity": "sha512-AuAGn1uxva5YBbBlXb+2JPxJRuemZsmlGcapPXWNSBNsQtAULfjioREGBWuI0EOvYUKjDnrCy8PW5Zlr1md5mw==", - "requires": { - "@jest/expect-utils": "^29.1.2", - "jest-get-type": "^29.0.0", - "jest-matcher-utils": "^29.1.2", - "jest-message-util": "^29.1.2", - "jest-util": "^29.1.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "jest-diff": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.1.2.tgz", - "integrity": "sha512-4GQts0aUopVvecIT4IwD/7xsBaMhKTYoM4/njE/aVw9wpw+pIUVp8Vab/KnSzSilr84GnLBkaP3JLDnQYCKqVQ==", - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.0.0", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.1.2" - } - }, - "jest-get-type": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.0.0.tgz", - "integrity": "sha512-83X19z/HuLKYXYHskZlBAShO7UfLFXu/vWajw9ZNJASN32li8yHMaVGAQqxFW1RCFOkB7cubaL6FaJVQqqJLSw==" - }, - "jest-matcher-utils": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.1.2.tgz", - "integrity": "sha512-MV5XrD3qYSW2zZSHRRceFzqJ39B2z11Qv0KPyZYxnzDHFeYZGJlgGi0SW+IXSJfOewgJp/Km/7lpcFT+cgZypw==", - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.1.2", - "jest-get-type": "^29.0.0", - "pretty-format": "^29.1.2" - } - }, - "jest-message-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.1.2.tgz", - "integrity": "sha512-9oJ2Os+Qh6IlxLpmvshVbGUiSkZVc2FK+uGOm6tghafnB2RyjKAxMZhtxThRMxfX1J1SOMhTn9oK3/MutRWQJQ==", - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.1.2", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.1.2", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-util": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.1.2.tgz", - "integrity": "sha512-vPCk9F353i0Ymx3WQq3+a4lZ07NXu9Ca8wya6o4Fe4/aO1e1awMMprZ3woPFpKwghEOW+UXgd15vVotuNN9ONQ==", - "requires": { - "@jest/types": "^29.1.2", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "pretty-format": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.1.2.tgz", - "integrity": "sha512-CGJ6VVGXVRP2o2Dorl4mAwwvDWT25luIsYhkyVQW32E4nL+TgW939J7LlKT/npq5Cpq6j3s+sy+13yk7xYpBmg==", - "requires": { - "@jest/schemas": "^29.0.0", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "@types/js-levenshtein": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz", - "integrity": "sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/leaflet": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.8.0.tgz", - "integrity": "sha512-+sXFmiJTFdhaXXIGFlV5re9AdqtAODoXbGAvxx02e5SHXL3ir7ClP5J7pahO8VmzKY3dth4RUS1nf2BTT+DW1A==", - "dev": true, - "requires": { - "@types/geojson": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, - "@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==" - }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", - "dev": true - }, - "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" - }, - "@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==", - "dev": true - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/react": { - "version": "18.0.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", - "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", - "requires": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "@types/react-dom": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", - "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", - "requires": { - "@types/react": "*" - } - }, - "@types/react-redux": { - "version": "7.1.24", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", - "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", - "requires": { - "@types/hoist-non-react-statics": "^3.3.0", - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0", - "redux": "^4.0.0" - } - }, - "@types/redux-logger": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@types/redux-logger/-/redux-logger-3.0.9.tgz", - "integrity": "sha512-cwYhVbYNgH01aepeMwhd0ABX6fhVB2rcQ9m80u8Fl50ZODhsZ8RhQArnLTkE7/Zrfq4Sz/taNoF7DQy9pCZSKg==", - "dev": true, - "requires": { - "redux": "^4.0.0" - } - }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/responselike": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", - "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", - "dev": true - }, - "@types/scheduler": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", - "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" - }, - "@types/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/set-cookie-parser": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/set-cookie-parser/-/set-cookie-parser-2.4.2.tgz", - "integrity": "sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/sockjs": { - "version": "0.3.33", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", - "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" - }, - "@types/testing-library__jest-dom": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.2.tgz", - "integrity": "sha512-vehbtyHUShPxIa9SioxDwCvgxukDMH//icJG90sXQBUm5lJOHLT5kNeU9tnivhnA/TkOFMzGIXN2cTc4hY8/kg==", - "requires": { - "@types/jest": "*" - } - }, - "@types/trusted-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz", - "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==", - "dev": true - }, - "@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" - }, - "@types/websocket": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.5.tgz", - "integrity": "sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/ws": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.1.tgz", - "integrity": "sha512-UxlLOfkuQnT2YSBCNq0x86SGOUxas6gAySFeDe2DcnEnA8655UIPoCDorWZCugcvKIL8IUI4oueUfJ1hhZSE2A==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.39.0.tgz", - "integrity": "sha512-xVfKOkBm5iWMNGKQ2fwX5GVgBuHmZBO1tCRwXmY5oAIsPscfwm2UADDuNB8ZVYCtpQvJK4xpjrK7jEhcJ0zY9A==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/type-utils": "5.39.0", - "@typescript-eslint/utils": "5.39.0", - "debug": "^4.3.4", - "ignore": "^5.2.0", - "regexpp": "^3.2.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/experimental-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.39.0.tgz", - "integrity": "sha512-n5N9kG/oGu2xXhHzsWzn94s6CWoiUj59FPU2dF2IQZxPftw+q6Jm5sV2vj5qTgAElRooHhrgtl2gxBQDCPt6WA==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "5.39.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", - "debug": "^4.3.4" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", - "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.39.0.tgz", - "integrity": "sha512-KJHJkOothljQWzR3t/GunL0TPKY+fGJtnpl+pX+sJ0YiKTz3q2Zr87SGTmFqsCMFrLt5E0+o+S6eQY0FAXj9uA==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.39.0", - "@typescript-eslint/utils": "5.39.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "@typescript-eslint/types": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", - "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", - "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "@typescript-eslint/utils": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.39.0.tgz", - "integrity": "sha512-+DnY5jkpOpgj+EBtYPyHRjXampJfC0yUZZzfzLuUWVZvCuKqSdJVC8UhdWipIw7VKNTfwfAPiOWzYkAwuIhiAg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", - "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.39.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@xmldom/xmldom": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.8.tgz", - "integrity": "sha512-0LNz4EY8B/8xXY86wMrQ4tz6zEHZv9ehFMJPm8u2gq5lQ71cfRKdaKyxfJAx5aUoyzx0qzgURblTisPGgz3d+Q==", - "dev": true - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "dev": true, - "optional": true - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-node": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", - "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", - "dev": true, - "requires": { - "acorn": "^7.0.0", - "acorn-walk": "^7.0.0", - "xtend": "^4.0.2" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, - "address": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/address/-/address-1.2.1.tgz", - "integrity": "sha512-B+6bi5D34+fDYENiH5qOlA0cV2rAGKuWZ9LeyUUehbXy8e0VS9e498yO0Jeeh+iM+6KbfudHTFjXw2MmJD4QRA==", - "dev": true - }, - "adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arg": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz", - "integrity": "sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" - } - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true - }, - "array-includes": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", - "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.flat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", - "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", - "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.2", - "es-shim-unscopables": "^1.0.0" - } - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true - }, - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "autoprefixer": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz", - "integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==", - "dev": true, - "requires": { - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001297", - "fraction.js": "^4.1.2", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "axe-core": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", - "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", - "dev": true - }, - "axios": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", - "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dev": true, - "requires": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", - "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz", - "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - } - }, - "babel-plugin-named-asset-import": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", - "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", - "dev": true, - "requires": {} - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, - "babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", - "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==", - "dev": true - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^27.5.1", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "babel-preset-react-app": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", - "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@babel/plugin-proposal-class-properties": "^7.16.0", - "@babel/plugin-proposal-decorators": "^7.16.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", - "@babel/plugin-proposal-numeric-separator": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.0", - "@babel/plugin-proposal-private-methods": "^7.16.0", - "@babel/plugin-transform-flow-strip-types": "^7.16.0", - "@babel/plugin-transform-react-display-name": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@babel/preset-react": "^7.16.0", - "@babel/preset-typescript": "^7.16.0", - "@babel/runtime": "^7.16.3", - "babel-plugin-macros": "^3.1.0", - "babel-plugin-transform-react-remove-prop-types": "^0.4.24" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bfj": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", - "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "check-types": "^11.1.1", - "hoopy": "^0.1.4", - "tryer": "^1.0.1" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, - "browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", - "dev": true - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", - "dev": true - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", - "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "check-types": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz", - "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ==", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==" - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "clean-css": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", - "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", - "dev": true - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dev": true, - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "colord": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz", - "integrity": "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==", - "dev": true - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "common-path-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", - "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", - "dev": true - }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", - "dev": true - }, - "core-js-compat": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", - "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", - "dev": true, - "requires": { - "browserslist": "^4.21.4" - } - }, - "core-js-pure": { - "version": "3.25.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", - "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cosmiconfig": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", - "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - } - }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "css-declaration-sorter": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz", - "integrity": "sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw==", - "dev": true, - "requires": { - "timsort": "^0.3.0" - } - }, - "css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "css-loader": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.6.0.tgz", - "integrity": "sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==", - "dev": true, - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.5", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.3.5" - } - }, - "css-minimizer-webpack-plugin": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", - "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", - "dev": true, - "requires": { - "cssnano": "^5.0.6", - "jest-worker": "^27.0.2", - "postcss": "^8.3.5", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", - "dev": true, - "requires": {} - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", - "dev": true - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dev": true, - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=" - }, - "csscolorparser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==", - "peer": true - }, - "cssdb": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-6.4.0.tgz", - "integrity": "sha512-8NMWrur/ewSNrRNZndbtOTXc2Xb2b+NCTPHj8VErFYvJUlgsMAiBGaFaxG6hjy9zbCjj2ZLwSQrMM+tormO8qA==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "cssnano": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.0.17.tgz", - "integrity": "sha512-fmjLP7k8kL18xSspeXTzRhaFtRI7DL9b8IcXR80JgtnWBpvAzHT7sCR/6qdn0tnxIaINUN6OEQu83wF57Gs3Xw==", - "dev": true, - "requires": { - "cssnano-preset-default": "^5.1.12", - "lilconfig": "^2.0.3", - "yaml": "^1.10.2" - } - }, - "cssnano-preset-default": { - "version": "5.1.12", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.12.tgz", - "integrity": "sha512-rO/JZYyjW1QNkWBxMGV28DW7d98UDLaF759frhli58QFehZ+D/LSmwQ2z/ylBAe2hUlsIWTq6NYGfQPq65EF9w==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.0.3", - "cssnano-utils": "^3.0.2", - "postcss-calc": "^8.2.0", - "postcss-colormin": "^5.2.5", - "postcss-convert-values": "^5.0.4", - "postcss-discard-comments": "^5.0.3", - "postcss-discard-duplicates": "^5.0.3", - "postcss-discard-empty": "^5.0.3", - "postcss-discard-overridden": "^5.0.4", - "postcss-merge-longhand": "^5.0.6", - "postcss-merge-rules": "^5.0.6", - "postcss-minify-font-values": "^5.0.4", - "postcss-minify-gradients": "^5.0.6", - "postcss-minify-params": "^5.0.5", - "postcss-minify-selectors": "^5.1.3", - "postcss-normalize-charset": "^5.0.3", - "postcss-normalize-display-values": "^5.0.3", - "postcss-normalize-positions": "^5.0.4", - "postcss-normalize-repeat-style": "^5.0.4", - "postcss-normalize-string": "^5.0.4", - "postcss-normalize-timing-functions": "^5.0.3", - "postcss-normalize-unicode": "^5.0.4", - "postcss-normalize-url": "^5.0.5", - "postcss-normalize-whitespace": "^5.0.4", - "postcss-ordered-values": "^5.0.5", - "postcss-reduce-initial": "^5.0.3", - "postcss-reduce-transforms": "^5.0.4", - "postcss-svgo": "^5.0.4", - "postcss-unique-selectors": "^5.0.4" - } - }, - "cssnano-utils": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.0.2.tgz", - "integrity": "sha512-KhprijuQv2sP4kT92sSQwhlK3SJTbDIsxcfIEySB0O+3m9esFOai7dP9bMx5enHAh2MwarVIcnwiWoOm01RIbQ==", - "dev": true, - "requires": {} - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dev": true, - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", - "dev": true - }, - "deep-diff": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", - "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=" - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", - "dev": true - }, - "default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "requires": { - "execa": "^5.0.0" - } - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", - "dev": true, - "requires": { - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dev": true, - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "detective": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", - "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", - "dev": true, - "requires": { - "acorn-node": "^1.6.1", - "defined": "^1.0.0", - "minimist": "^1.1.1" - } - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-accessibility-api": { - "version": "0.5.12", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.12.tgz", - "integrity": "sha512-gQ2mON6fLWZeM8ubjzL7RtMeHS/g8hb82j4MjHmcQECD7pevWsMlhqwp9BjIRrQvmyJMMyv/XiO1cXzeFlUw4g==" - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dev": true, - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true - }, - "dotenv-expand": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", - "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", - "dev": true - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==", - "peer": true - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "ejs": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.7.tgz", - "integrity": "sha512-BIar7R6abbUxDA3bfXrO4DSgwo8I+fB5/1zgujl3HLLjwd6+9iOnrT+t3grn2qbk9vOgBubXOFwX2m9axoFaGw==", - "dev": true, - "requires": { - "jake": "^10.8.5" - } - }, - "electron": { - "version": "22.3.25", - "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.25.tgz", - "integrity": "sha512-AjrP7bebMs/IPsgmyowptbA7jycTkrJC7jLZTb5JoH30PkBC6pZx/7XQ0aDok82SsmSiF4UJDOg+HoLrEBiqmg==", - "dev": true, - "requires": { - "@electron/get": "^2.0.0", - "@types/node": "^16.11.26", - "extract-zip": "^2.0.1" - }, - "dependencies": { - "@types/node": { - "version": "16.11.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.64.tgz", - "integrity": "sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==", - "dev": true - } - } - }, - "electron-is-dev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz", - "integrity": "sha512-3X99K852Yoqu9AcW50qz3ibYBWY79/pBhlMCab8ToEWS48R0T9tyxRiQhwylE7zQdXrMnx2JKqUJyMPmt5FBqA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.4.275", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.275.tgz", - "integrity": "sha512-aJeQQ+Hl9Jyyzv4chBqYJwmVRY46N5i2BEX5Cuyk/5gFCUZ5F3i7Hnba6snZftWla7Gglwc5pIgcd+E7cW+rPg==", - "dev": true - }, - "electron-window-state": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/electron-window-state/-/electron-window-state-5.0.3.tgz", - "integrity": "sha512-1mNTwCfkolXl3kMf50yW3vE2lZj0y92P/HYWFBrb+v2S/pCka5mdwN3cagKm458A7NjndSwijynXgcLWRodsVg==", - "requires": { - "jsonfile": "^4.0.0", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - } - } - }, - "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-stack-parser": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.7.tgz", - "integrity": "sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA==", - "dev": true, - "requires": { - "stackframe": "^1.1.1" - } - }, - "es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.3", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", - "unbox-primitive": "^1.0.2" - } - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true - }, - "es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", - "dev": true - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.10.0.tgz", - "integrity": "sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.2.0", - "@humanwhocodes/config-array": "^0.9.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", - "globals": "^13.6.0", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "eslint-config-react-app": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", - "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@babel/eslint-parser": "^7.16.3", - "@rushstack/eslint-patch": "^1.1.0", - "@typescript-eslint/eslint-plugin": "^5.5.0", - "@typescript-eslint/parser": "^5.5.0", - "babel-preset-react-app": "^10.0.1", - "confusing-browser-globals": "^1.0.11", - "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jest": "^25.3.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.27.1", - "eslint-plugin-react-hooks": "^4.3.0", - "eslint-plugin-testing-library": "^5.0.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-module-utils": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", - "dev": true, - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-flowtype": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", - "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", - "dev": true, - "requires": { - "lodash": "^4.17.21", - "string-natural-compare": "^3.0.1" - } - }, - "eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "requires": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "eslint-plugin-jest": { - "version": "25.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", - "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "^5.0.0" - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", - "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", - "dev": true, - "requires": { - "@babel/runtime": "^7.18.9", - "aria-query": "^4.2.2", - "array-includes": "^3.1.5", - "ast-types-flow": "^0.0.7", - "axe-core": "^4.4.3", - "axobject-query": "^2.2.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "has": "^1.0.3", - "jsx-ast-utils": "^3.3.2", - "language-tags": "^1.0.5", - "minimatch": "^3.1.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "array.prototype.flatmap": "^1.3.0", - "doctrine": "^2.1.0", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.5", - "object.fromentries": "^2.0.5", - "object.hasown": "^1.1.1", - "object.values": "^1.1.5", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.7" - }, - "dependencies": { - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "requires": {} - }, - "eslint-plugin-testing-library": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.7.2.tgz", - "integrity": "sha512-0ZmHeR/DUUgEzW8rwUBRWxuqntipDtpvxK0hymdHnLlABryJkzd+CAHr+XnISaVsTisZ5MLHp6nQF+8COHLLTA==", - "dev": true, - "requires": { - "@typescript-eslint/utils": "^5.13.0" - } - }, - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "eslint-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", - "dev": true, - "requires": { - "@types/eslint": "^7.28.2", - "jest-worker": "^27.3.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "schema-utils": "^3.1.1" - } - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "dev": true - }, - "espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", - "dev": true, - "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "esri-leaflet": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/esri-leaflet/-/esri-leaflet-3.0.8.tgz", - "integrity": "sha512-mLb4pRfDAbkG1YhuajD22erLXIAtrF1R32hmgmlJNI3t47n6KjTppCb8lViia0O7+GDORXFuJ9Lj9RkpsaKhSA==", - "requires": { - "@terraformer/arcgis": "^2.1.0", - "tiny-binary-search": "^1.0.3" - } - }, - "esri-leaflet-cluster": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/esri-leaflet-cluster/-/esri-leaflet-cluster-3.0.0.tgz", - "integrity": "sha512-aAj2Bv7Lv8e4uK/BLT5EJlIizk+28NSSYbkYcPT+HYrnmLwog01V7pGxGOmI3HMpDMTjlt8WE9DpygMy6TIwQQ==", - "peer": true, - "requires": {} - }, - "esri-leaflet-geocoder": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esri-leaflet-geocoder/-/esri-leaflet-geocoder-3.1.3.tgz", - "integrity": "sha512-XuorBaPKOq2XBswyWS3fX4I0EyGamdQsao/NQbn+9wlCZtpDrpIn2iKLY7x4uOaPC4wCjE/rskli8UMCVwlZrg==", - "peer": true, - "requires": { - "esri-leaflet": "^3.0.2", - "leaflet": "^1.0.0" - } - }, - "esri-leaflet-heatmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/esri-leaflet-heatmap/-/esri-leaflet-heatmap-2.0.1.tgz", - "integrity": "sha512-Yd6gNghJfG5Zv7+5A0SraqIMK6nqYSAkF925DXnpbi5BFbI8vbJFK8JyG9hFq+vC/iBtCCpQyGz0UjtHMzNrPg==", - "peer": true, - "requires": { - "leaflet": "^1.0.0-rc.3", - "leaflet.heat": "^0.2.0" - } - }, - "esri-leaflet-vector": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/esri-leaflet-vector/-/esri-leaflet-vector-3.1.5.tgz", - "integrity": "sha512-XNRkrqfB4xKGQfRtjiMJsxwF4oiPnSNngQJrLBbMQMadLqcy+mZRAbDHDx/KEK6S0w0QoM4/A+A2rcNHHBQKlA==", - "peer": true, - "requires": { - "mapbox-gl": "1.13.1" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" - } - }, - "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", - "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.19.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.2", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.7", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", - "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - } - }, - "filelist": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.3.tgz", - "integrity": "sha512-LwjCsruLWQULGYKy7TX0OPtrL9kLpojOFKc5VCTxdFTV7w5zbsgqVKfnkKG7Qgjtq50gKfO56hJv88OfcGb70Q==", - "dev": true, - "requires": { - "minimatch": "^5.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "filesize": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", - "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", - "dev": true - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", - "dev": true - }, - "follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "fork-ts-checker-webpack-plugin": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", - "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "chokidar": "^3.4.2", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "glob": "^7.1.6", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true - } - } - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fraction.js": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.3.tgz", - "integrity": "sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs-monkey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", - "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "generate-license-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-license-file/-/generate-license-file-2.0.0.tgz", - "integrity": "sha512-GutXlMEwS6cxXhd6G7FM6iyzGVnN23S0m3Z3GI6cabqrE4lb5Ebzx2nxW0bXyPYMsHjBBzbM6xx+ZLhe7CI7Xg==", - "dev": true, - "requires": { - "arg": "^5.0.0", - "cli-spinners": "^2.6.0", - "enquirer": "^2.3.6", - "esm": "^3.2.25", - "license-checker": "^25.0.1", - "ora": "^5.4.1" - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "geojson-vt": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-3.2.1.tgz", - "integrity": "sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==", - "peer": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==", - "peer": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "optional": true, - "requires": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - } - }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "requires": { - "global-prefix": "^3.0.0" - } - }, - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "optional": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "graphql": { - "version": "16.7.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.7.1.tgz", - "integrity": "sha512-DRYR9tf+UGU0KOsMcKAlXeFfX89UiiIZ0dRU3mR0yJfu6OjZqUcp68NnFLnqQU5RexygFoDy1EW+ccOYcPfmHg==", - "dev": true - }, - "grid-index": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/grid-index/-/grid-index-1.1.0.tgz", - "integrity": "sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==", - "peer": true - }, - "gzip-size": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", - "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", - "dev": true, - "requires": { - "duplexer": "^0.1.2" - } - }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "headers-polyfill": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.1.2.tgz", - "integrity": "sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==", - "dev": true - }, - "hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "requires": { - "react-is": "^16.7.0" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, - "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", - "dev": true, - "requires": { - "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", - "param-case": "^3.0.4", - "relateurl": "^0.2.7", - "terser": "^5.10.0" - } - }, - "html-webpack-plugin": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", - "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", - "dev": true, - "requires": { - "@types/html-minifier-terser": "^6.0.0", - "html-minifier-terser": "^6.0.2", - "lodash": "^4.17.21", - "pretty-error": "^4.0.0", - "tapable": "^2.0.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "http-proxy-middleware": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.3.tgz", - "integrity": "sha512-1bloEwnrHMnCoO/Gcwbz7eSVvW50KPES01PecpagI+YLNLci4AcuKJrujW4Mc3sBLpFxMSlsLNHS5Nl/lvrTPA==", - "dev": true, - "requires": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - } - }, - "http2-client": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", - "integrity": "sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==", - "dev": true - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} - }, - "idb": { - "version": "6.1.5", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", - "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==", - "dev": true - }, - "identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", - "dev": true, - "requires": { - "harmony-reflect": "^1.4.6" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true - }, - "immer": { - "version": "9.0.12", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz", - "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==" - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "inquirer": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", - "integrity": "sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", - "dev": true - }, - "ipaddr.js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", - "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", - "dev": true - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true - }, - "is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true - }, - "is-root": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", - "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "requires": { - "is-docker": "^2.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.4.tgz", - "integrity": "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jake": { - "version": "10.8.5", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", - "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", - "dev": true, - "requires": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.1", - "minimatch": "^3.0.4" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=", - "dev": true - }, - "jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", - "dev": true, - "requires": { - "@jest/core": "^27.5.1", - "import-local": "^3.0.2", - "jest-cli": "^27.5.1" - } - }, - "jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "execa": "^5.0.0", - "throat": "^6.0.1" - } - }, - "jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "requires": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", - "dev": true, - "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - } - }, - "jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true - }, - "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dev": true, - "requires": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" - } - }, - "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", - "dev": true - }, - "jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - } - }, - "jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", - "dev": true, - "requires": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - } - }, - "jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dev": true, - "requires": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-transform-stub": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz", - "integrity": "sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==", - "dev": true - }, - "jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watch-typeahead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.0.0.tgz", - "integrity": "sha512-jxoszalAb394WElmiJTFBMzie/RDCF+W7Q29n5LzOPtcoQoHWfdUtHFkbhgf5NwWe8uMOxvKb/g7ea7CshfkTw==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.1", - "chalk": "^4.0.0", - "jest-regex-util": "^27.0.0", - "jest-watcher": "^27.0.0", - "slash": "^4.0.0", - "string-length": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", - "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - }, - "string-length": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", - "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", - "dev": true, - "requires": { - "char-regex": "^2.0.0", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "requires": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "joi": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.6.0.tgz", - "integrity": "sha512-OX5dG6DTbcr/kbMFj0KGYxuew69HPcAE3K/sZpEV2nP6e/j/C0HV+HNiBPCASxdx5T7DMoa0s8UeHWMnb6n2zw==", - "dev": true, - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.0", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "optional": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonpointer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.0.tgz", - "integrity": "sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg==", - "dev": true - }, - "jsx-ast-utils": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", - "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, - "requires": { - "array-includes": "^3.1.5", - "object.assign": "^4.1.3" - } - }, - "kdbush": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-3.0.0.tgz", - "integrity": "sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==", - "peer": true - }, - "keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "klona": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", - "dev": true - }, - "language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dev": true, - "requires": { - "language-subtag-registry": "~0.3.2" - } - }, - "leaflet": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.2.tgz", - "integrity": "sha512-Kc77HQvWO+y9y2oIs3dn5h5sy2kr3j41ewdqCMEUA4N89lgfUUfOBy7wnnHEstDpefiGFObq12FdopGRMx4J7g==" - }, - "leaflet-ruler": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/leaflet-ruler/-/leaflet-ruler-1.0.0.tgz", - "integrity": "sha512-5Ti99czL+hhcd5rMmT5JBkDvzErPUM+ogJbP6NDzJEMK5vCGqS9/1BrMpVeCcCaxViSWLPf9qcXRGcGO85UCZA==", - "requires": {} - }, - "leaflet.heat": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/leaflet.heat/-/leaflet.heat-0.2.0.tgz", - "integrity": "sha512-Cd5PbAA/rX3X3XKxfDoUGi9qp78FyhWYurFg3nsfhntcM/MCNK08pRkf4iEenO1KNqwVPKCmkyktjW3UD+h9bQ==", - "peer": true - }, - "leaflet.markercluster": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/leaflet.markercluster/-/leaflet.markercluster-1.5.3.tgz", - "integrity": "sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==", - "peer": true, - "requires": {} - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "license-checker": { - "version": "25.0.1", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-25.0.1.tgz", - "integrity": "sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "read-installed": "~4.0.3", - "semver": "^5.5.0", - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-satisfies": "^4.0.0", - "treeify": "^1.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true - }, - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "requires": { - "tslib": "^2.0.3" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "lz-string": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=" - }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "mapbox-gl": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-1.13.1.tgz", - "integrity": "sha512-GSyubcoSF5MyaP8z+DasLu5v7KmDK2pp4S5+VQ5WdVQUOaAqQY4jwl4JpcdNho3uWm2bIKs7x1l7q3ynGmW60g==", - "peer": true, - "requires": { - "@mapbox/geojson-rewind": "^0.5.0", - "@mapbox/geojson-types": "^1.0.2", - "@mapbox/jsonlint-lines-primitives": "^2.0.2", - "@mapbox/mapbox-gl-supported": "^1.5.0", - "@mapbox/point-geometry": "^0.1.0", - "@mapbox/tiny-sdf": "^1.1.1", - "@mapbox/unitbezier": "^0.0.0", - "@mapbox/vector-tile": "^1.3.1", - "@mapbox/whoots-js": "^3.1.0", - "csscolorparser": "~1.0.3", - "earcut": "^2.2.2", - "geojson-vt": "^3.2.1", - "gl-matrix": "^3.2.1", - "grid-index": "^1.1.0", - "minimist": "^1.2.5", - "murmurhash-js": "^1.0.0", - "pbf": "^3.2.1", - "potpack": "^1.0.1", - "quickselect": "^2.0.0", - "rw": "^1.3.3", - "supercluster": "^7.1.0", - "tinyqueue": "^2.0.3", - "vt-pbf": "^3.1.1" - } - }, - "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "optional": true, - "requires": { - "escape-string-regexp": "^4.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true - } - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", - "dev": true, - "requires": { - "fs-monkey": "1.0.3" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "milsymbol": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/milsymbol/-/milsymbol-2.0.0.tgz", - "integrity": "sha512-GcBFrcIUr8jScaZqZb0SI2W6AbnUrPCTHu2kqHxduQjN2DIN8q5pY6ksSWfnJ4HlcIAWQhyotbdPIr1bBxFbwQ==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==" - }, - "mini-css-extract-plugin": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", - "integrity": "sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==", - "dev": true, - "requires": { - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "msw": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/msw/-/msw-1.2.2.tgz", - "integrity": "sha512-GsW3PE/Es/a1tYThXcM8YHOZ1S1MtivcS3He/LQbbTCx3rbWJYCtWD5XXyJ53KlNPT7O1VI9sCW3xMtgFe8XpQ==", - "dev": true, - "requires": { - "@mswjs/cookies": "^0.2.2", - "@mswjs/interceptors": "^0.17.5", - "@open-draft/until": "^1.0.3", - "@types/cookie": "^0.4.1", - "@types/js-levenshtein": "^1.1.1", - "chalk": "4.1.1", - "chokidar": "^3.4.2", - "cookie": "^0.4.2", - "graphql": "^15.0.0 || ^16.0.0", - "headers-polyfill": "^3.1.2", - "inquirer": "^8.2.0", - "is-node-process": "^1.2.0", - "js-levenshtein": "^1.1.6", - "node-fetch": "^2.6.7", - "outvariant": "^1.4.0", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.4.3", - "type-fest": "^2.19.0", - "yargs": "^17.3.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "murmurhash-js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz", - "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==", - "peer": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dev": true, - "requires": { - "http2-client": "^1.2.5" - } - }, - "node-forge": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.0.tgz", - "integrity": "sha512-08ARB91bUi6zNKzVmaj3QO7cr397uiDT2nJ63cHjyNtCTWIgvS47j3eT0WfzUwS9+6Z5YshRaoasFkXCKrIYbA==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-readfiles": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==", - "dev": true, - "requires": { - "es6-promise": "^3.2.1" - } - }, - "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", - "dev": true - }, - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "dev": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "oas-kit-common": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", - "dev": true, - "requires": { - "fast-safe-stringify": "^2.0.7" - } - }, - "oas-linter": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.2.tgz", - "integrity": "sha512-KEGjPDVoU5K6swgo9hJVA/qYGlwfbFx+Kg2QB/kd7rzV5N8N5Mg6PlsoCMohVnQmo+pzJap/F610qTodKzecGQ==", - "dev": true, - "requires": { - "@exodus/schemasafe": "^1.0.0-rc.2", - "should": "^13.2.1", - "yaml": "^1.10.0" - } - }, - "oas-resolver": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.6.tgz", - "integrity": "sha512-Yx5PWQNZomfEhPPOphFbZKi9W93CocQj18NlD2Pa4GWZzdZpSJvYwoiuurRI7m3SpcChrnO08hkuQDL3FGsVFQ==", - "dev": true, - "requires": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "dependencies": { - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, - "oas-schema-walker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", - "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", - "dev": true - }, - "oas-validator": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.8.tgz", - "integrity": "sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.8", - "oas-linter": "^3.2.2", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "reftools": "^1.1.9", - "should": "^13.2.1", - "yaml": "^1.10.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "dev": true - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.entries": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", - "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.fromentries": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", - "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.hasown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", - "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", - "dev": true, - "requires": { - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - } - }, - "openapi-types": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.0.2.tgz", - "integrity": "sha512-GuTo7FyZjOIWVhIhQSWJVaws6A82sWIGyQogxxYBYKZ0NBdyP2CYSIgOwFfSB+UVoPExk/YzFpyYitHS8KVZtA==", - "dev": true, - "peer": true - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "outvariant": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", - "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==", - "dev": true - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", - "dev": true, - "requires": { - "@types/retry": "^0.12.0", - "retry": "^0.13.1" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pbf": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", - "peer": true, - "requires": { - "ieee754": "^1.1.12", - "resolve-protobuf-schema": "^2.1.0" - } - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "pkg-up": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", - "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true - } - } - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dev": true, - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "postcss": { - "version": "8.4.7", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.7.tgz", - "integrity": "sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A==", - "dev": true, - "requires": { - "nanoid": "^3.3.1", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-attribute-case-insensitive": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.0.tgz", - "integrity": "sha512-b4g9eagFGq9T5SWX4+USfVyjIb3liPnjhHHRMP7FMB2kFVpYyfEscV0wP3eaXhKlcHKUut8lt5BGoeylWA/dBQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.2" - } - }, - "postcss-browser-comments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", - "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", - "dev": true, - "requires": {} - }, - "postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-clamp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.0.0.tgz", - "integrity": "sha512-FsMmeBZtymFN7Jtlnw9is8I4nB+qEEb/qS0ZLTIqcKiwZyHBq44Yhv29Q+VQsTGHYFqIr/s/9tqvNM7j+j1d+g==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-color-functional-notation": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.2.tgz", - "integrity": "sha512-DXVtwUhIk4f49KK5EGuEdgx4Gnyj6+t2jBSEmxvpIK9QI40tWrpS2Pua8Q7iIZWBrki2QOaeUdEaLPPa91K0RQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-color-hex-alpha": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.3.tgz", - "integrity": "sha512-fESawWJCrBV035DcbKRPAVmy21LpoyiXdPTuHUfWJ14ZRjY7Y7PA6P4g8z6LQGYhU1WAxkTxjIjurXzoe68Glw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-color-rebeccapurple": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.0.2.tgz", - "integrity": "sha512-SFc3MaocHaQ6k3oZaFwH8io6MdypkUtEy/eXzXEB1vEQlO3S3oDc/FSZA8AsS04Z25RirQhlDlHLh3dn7XewWw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-colormin": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.5.tgz", - "integrity": "sha512-+X30aDaGYq81mFqwyPpnYInsZQnNpdxMX0ajlY7AExCexEFkPVV+KrO7kXwayqEWL2xwEbNQ4nUO0ZsRWGnevg==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.4.tgz", - "integrity": "sha512-bugzSAyjIexdObovsPZu/sBCTHccImJxLyFgeV0MmNBm/Lw5h5XnjfML6gzEmJ3A6nyfCW7hb1JXzcsA4Zfbdw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-custom-media": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.0.tgz", - "integrity": "sha512-FvO2GzMUaTN0t1fBULDeIvxr5IvbDXcIatt6pnJghc736nqNgsGao5NT+5+WVLAQiTt6Cb3YUms0jiPaXhL//g==", - "dev": true, - "requires": {} - }, - "postcss-custom-properties": { - "version": "12.1.4", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.4.tgz", - "integrity": "sha512-i6AytuTCoDLJkWN/MtAIGriJz3j7UX6bV7Z5t+KgFz+dwZS15/mlTJY1S0kRizlk6ba0V8u8hN50Fz5Nm7tdZw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-custom-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.0.tgz", - "integrity": "sha512-/1iyBhz/W8jUepjGyu7V1OPcGbc636snN1yXEQCinb6Bwt7KxsiU7/bLQlp8GwAXzCh7cobBU5odNn/2zQWR8Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-dir-pseudo-class": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.4.tgz", - "integrity": "sha512-I8epwGy5ftdzNWEYok9VjW9whC4xnelAtbajGv4adql4FIF09rnrxnA9Y8xSHN47y7gqFIv10C5+ImsLeJpKBw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "postcss-discard-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.3.tgz", - "integrity": "sha512-6W5BemziRoqIdAKT+1QjM4bNcJAQ7z7zk073730NHg4cUXh3/rQHHj7pmYxUB9aGhuRhBiUf0pXvIHkRwhQP0Q==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.3.tgz", - "integrity": "sha512-vPtm1Mf+kp7iAENTG7jI1MN1lk+fBqL5y+qxyi4v3H+lzsXEdfS3dwUZD45KVhgzDEgduur8ycB4hMegyMTeRw==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.3.tgz", - "integrity": "sha512-xGJugpaXKakwKI7sSdZjUuN4V3zSzb2Y0LOlmTajFbNinEjTfVs9PFW2lmKBaC/E64WwYppfqLD03P8l9BuueA==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.4.tgz", - "integrity": "sha512-3j9QH0Qh1KkdxwiZOW82cId7zdwXVQv/gRXYDnwx5pBtR1sTkU4cXRK9lp5dSdiM0r0OICO/L8J6sV1/7m0kHg==", - "dev": true, - "requires": {} - }, - "postcss-double-position-gradients": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.0.tgz", - "integrity": "sha512-oz73I08yMN3oxjj0s8mED1rG+uOYoK3H8N9RjQofyg52KBRNmePJKg3fVwTpL2U5ZFbCzXoZBsUD/CvZdlqE4Q==", - "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-env-function": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.5.tgz", - "integrity": "sha512-gPUJc71ji9XKyl0WSzAalBeEA/89kU+XpffpPxSaaaZ1c48OL36r1Ep5R6+9XAPkIiDlSvVAwP4io12q/vTcvA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-flexbugs-fixes": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", - "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", - "dev": true, - "requires": {} - }, - "postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "requires": {} - }, - "postcss-gap-properties": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.3.tgz", - "integrity": "sha512-rPPZRLPmEKgLk/KlXMqRaNkYTUpE7YC+bOIQFN5xcu1Vp11Y4faIXv6/Jpft6FMnl6YRxZqDZG0qQOW80stzxQ==", - "dev": true, - "requires": {} - }, - "postcss-image-set-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.6.tgz", - "integrity": "sha512-KfdC6vg53GC+vPd2+HYzsZ6obmPqOk6HY09kttU19+Gj1nC3S3XBVEXDHxkhxTohgZqzbUb94bKXvKDnYWBm/A==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "requires": {} - }, - "postcss-js": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", - "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", - "dev": true, - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-lab-function": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.1.1.tgz", - "integrity": "sha512-j3Z0WQCimY2tMle++YcmygnnVbt6XdnrCV1FO2IpzaCSmtTF2oO8h4ZYUA1Q+QHYroIiaWPvNHt9uBR4riCksQ==", - "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-load-config": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.3.tgz", - "integrity": "sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw==", - "dev": true, - "requires": { - "lilconfig": "^2.0.4", - "yaml": "^1.10.2" - } - }, - "postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", - "dev": true, - "requires": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - } - }, - "postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true, - "requires": {} - }, - "postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "requires": {} - }, - "postcss-merge-longhand": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.6.tgz", - "integrity": "sha512-rkmoPwQO6ymJSmWsX6l2hHeEBQa7C4kJb9jyi5fZB1sE8nSCv7sqchoYPixRwX/yvLoZP2y6FA5kcjiByeJqDg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^5.0.3" - } - }, - "postcss-merge-rules": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.6.tgz", - "integrity": "sha512-nzJWJ9yXWp8AOEpn/HFAW72WKVGD2bsLiAmgw4hDchSij27bt6TF+sIK0cJUBAYT3SGcjtGGsOR89bwkkMuMgQ==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^3.0.2", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.4.tgz", - "integrity": "sha512-RN6q3tyuEesvyCYYFCRGJ41J1XFvgV+dvYGHr0CeHv8F00yILlN8Slf4t8XW4IghlfZYCeyRrANO6HpJ948ieA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.6.tgz", - "integrity": "sha512-E/dT6oVxB9nLGUTiY/rG5dX9taugv9cbLNTFad3dKxOO+BQg25Q/xo2z2ddG+ZB1CbkZYaVwx5blY8VC7R/43A==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.5.tgz", - "integrity": "sha512-YBNuq3Rz5LfLFNHb9wrvm6t859b8qIqfXsWeK7wROm3jSKNpO1Y5e8cOyBv6Acji15TgSrAwb3JkVNCqNyLvBg==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.3.tgz", - "integrity": "sha512-9RJfTiQEKA/kZhMaEXND893nBqmYQ8qYa/G+uPdVnXF6D/FzpfI6kwBtWEcHx5FqDbA79O9n6fQJfrIj6M8jvQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} - }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - } - }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - } - }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } - }, - "postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.6" - } - }, - "postcss-nesting": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.1.2.tgz", - "integrity": "sha512-dJGmgmsvpzKoVMtDMQQG/T6FSqs6kDtUDirIfl4KnjMCiY9/ETX8jdKyCd20swSRAbUYkaBKV20pxkzxoOXLqQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.8" - } - }, - "postcss-normalize": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", - "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", - "dev": true, - "requires": { - "@csstools/normalize.css": "*", - "postcss-browser-comments": "^4", - "sanitize.css": "*" - } - }, - "postcss-normalize-charset": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.3.tgz", - "integrity": "sha512-iKEplDBco9EfH7sx4ut7R2r/dwTnUqyfACf62Unc9UiyFuI7uUqZZtY+u+qp7g8Qszl/U28HIfcsI3pEABWFfA==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.3.tgz", - "integrity": "sha512-FIV5FY/qs4Ja32jiDb5mVj5iWBlS3N8tFcw2yg98+8MkRgyhtnBgSC0lxU+16AMHbjX5fbSJgw5AXLMolonuRQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.4.tgz", - "integrity": "sha512-qynirjBX0Lc73ROomZE3lzzmXXTu48/QiEzKgMeqh28+MfuHLsuqC9po4kj84igZqqFGovz8F8hf44hA3dPYmQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.4.tgz", - "integrity": "sha512-Innt+wctD7YpfeDR7r5Ik6krdyppyAg2HBRpX88fo5AYzC1Ut/l3xaxACG0KsbX49cO2n5EB13clPwuYVt8cMA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.4.tgz", - "integrity": "sha512-Dfk42l0+A1CDnVpgE606ENvdmksttLynEqTQf5FL3XGQOyqxjbo25+pglCUvziicTxjtI2NLUR6KkxyUWEVubQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.3.tgz", - "integrity": "sha512-QRfjvFh11moN4PYnJ7hia4uJXeFotyK3t2jjg8lM9mswleGsNw2Lm3I5wO+l4k1FzK96EFwEVn8X8Ojrp2gP4g==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.4.tgz", - "integrity": "sha512-W79Regn+a+eXTzB+oV/8XJ33s3pDyFTND2yDuUCo0Xa3QSy1HtNIfRVPXNubHxjhlqmMFADr3FSCHT84ITW3ig==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.5.tgz", - "integrity": "sha512-Ws3tX+PcekYlXh+ycAt0wyzqGthkvVtZ9SZLutMVvHARxcpu4o7vvXcNoiNKyjKuWecnjS6HDI3fjBuDr5MQxQ==", - "dev": true, - "requires": { - "normalize-url": "^6.0.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.4.tgz", - "integrity": "sha512-wsnuHolYZjMwWZJoTC9jeI2AcjA67v4UuidDrPN9RnX8KIZfE+r2Nd6XZRwHVwUiHmRvKQtxiqo64K+h8/imaw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-opacity-percentage": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", - "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", - "dev": true - }, - "postcss-ordered-values": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.5.tgz", - "integrity": "sha512-mfY7lXpq+8bDEHfP+muqibDPhZ5eP9zgBEF9XRvoQgXcQe2Db3G1wcvjbnfjXG6wYsl+0UIjikqq4ym1V2jGMQ==", - "dev": true, - "requires": { - "cssnano-utils": "^3.0.2", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-overflow-shorthand": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.3.tgz", - "integrity": "sha512-CxZwoWup9KXzQeeIxtgOciQ00tDtnylYIlJBBODqkgS/PU2jISuWOL/mYLHmZb9ZhZiCaNKsCRiLp22dZUtNsg==", - "dev": true, - "requires": {} - }, - "postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "requires": {} - }, - "postcss-place": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.4.tgz", - "integrity": "sha512-MrgKeiiu5OC/TETQO45kV3npRjOFxEHthsqGtkh3I1rPbZSbXGD/lZVi9j13cYh+NA8PIAPyk6sGjT9QbRyvSg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-preset-env": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.4.1.tgz", - "integrity": "sha512-UvBVvPJ2vb4odAtckSbryndyBz+Me1q8wawqq0qznpDXy188I+8W5Sa929sCPqw2/NSYnqpHJbo41BKso3+I9A==", - "dev": true, - "requires": { - "@csstools/postcss-color-function": "^1.0.2", - "@csstools/postcss-font-format-keywords": "^1.0.0", - "@csstools/postcss-hwb-function": "^1.0.0", - "@csstools/postcss-ic-unit": "^1.0.0", - "@csstools/postcss-is-pseudo-class": "^2.0.0", - "@csstools/postcss-normalize-display-values": "^1.0.0", - "@csstools/postcss-oklab-function": "^1.0.1", - "@csstools/postcss-progressive-custom-properties": "^1.2.0", - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "css-blank-pseudo": "^3.0.3", - "css-has-pseudo": "^3.0.4", - "css-prefers-color-scheme": "^6.0.3", - "cssdb": "^6.3.1", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-clamp": "^4.0.0", - "postcss-color-functional-notation": "^4.2.2", - "postcss-color-hex-alpha": "^8.0.3", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.4", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.4", - "postcss-double-position-gradients": "^3.1.0", - "postcss-env-function": "^4.0.5", - "postcss-focus-visible": "^6.0.4", - "postcss-focus-within": "^5.0.4", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.3", - "postcss-image-set-function": "^4.0.6", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.1.1", - "postcss-logical": "^5.0.4", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-opacity-percentage": "^1.1.2", - "postcss-overflow-shorthand": "^3.0.3", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.4", - "postcss-pseudo-class-any-link": "^7.1.1", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - } - }, - "postcss-pseudo-class-any-link": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.1.tgz", - "integrity": "sha512-JRoLFvPEX/1YTPxRxp1JO4WxBVXJYrSY7NHeak5LImwJ+VobFMwYDQHvfTXEpcn+7fYIeGkC29zYFhFWIZD8fg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - } - }, - "postcss-reduce-initial": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.3.tgz", - "integrity": "sha512-c88TkSnQ/Dnwgb4OZbKPOBbCaauwEjbECP5uAuFPOzQ+XdjNjRH7SG0dteXrpp1LlIFEKK76iUGgmw2V0xeieA==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.4.tgz", - "integrity": "sha512-VIJB9SFSaL8B/B7AXb7KHL6/GNNbbCHslgdzS9UDfBZYIA2nx8NLY7iD/BXFSO/1sRUILzBTfHCoW5inP37C5g==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "requires": {} - }, - "postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.4.tgz", - "integrity": "sha512-yDKHvULbnZtIrRqhZoA+rxreWpee28JSRH/gy9727u0UCgtpv1M/9WEWY3xySlFa0zQJcqf6oCBJPR5NwkmYpg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^2.7.0" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - }, - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dev": true, - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "svgo": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", - "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", - "dev": true, - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^4.1.3", - "css-tree": "^1.1.3", - "csso": "^4.2.0", - "picocolors": "^1.0.0", - "stable": "^0.1.8" - } - } - } - }, - "postcss-unique-selectors": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.4.tgz", - "integrity": "sha512-5ampwoSDJCxDPoANBIlMgoBcYUHnhaiuLYJR5pj1DLnYQvMRVyFuTA5C3Bvt+aHtiqWpJkD/lXT50Vo1D0ZsAQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "potpack": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz", - "integrity": "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==", - "peer": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", - "dev": true - }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true - }, - "pretty-error": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", - "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", - "dev": true, - "requires": { - "lodash": "^4.17.20", - "renderkid": "^3.0.0" - } - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" - } - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", - "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", - "dev": true, - "requires": { - "asap": "~2.0.6" - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true - } - } - }, - "protocol-buffers-schema": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==", - "peer": true - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "dependencies": { - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - } - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", - "peer": true - }, - "raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, - "requires": { - "performance-now": "^2.1.0" - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "react-app-polyfill": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", - "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", - "dev": true, - "requires": { - "core-js": "^3.19.2", - "object-assign": "^4.1.1", - "promise": "^8.1.0", - "raf": "^3.4.1", - "regenerator-runtime": "^0.13.9", - "whatwg-fetch": "^3.6.2" - } - }, - "react-dev-utils": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", - "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.0", - "address": "^1.1.2", - "browserslist": "^4.18.1", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "detect-port-alt": "^1.1.6", - "escape-string-regexp": "^4.0.0", - "filesize": "^8.0.6", - "find-up": "^5.0.0", - "fork-ts-checker-webpack-plugin": "^6.5.0", - "global-modules": "^2.0.0", - "globby": "^11.0.4", - "gzip-size": "^6.0.0", - "immer": "^9.0.7", - "is-root": "^2.1.0", - "loader-utils": "^3.2.0", - "open": "^8.4.0", - "pkg-up": "^3.1.0", - "prompts": "^2.4.2", - "react-error-overlay": "^6.0.11", - "recursive-readdir": "^2.2.2", - "shell-quote": "^1.7.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "requires": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - } - }, - "react-error-overlay": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", - "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==", - "dev": true - }, - "react-esri-leaflet": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/react-esri-leaflet/-/react-esri-leaflet-2.0.1.tgz", - "integrity": "sha512-5keSefL7gfEIK+QTfxJ/sZ+Fve8zk9zfT1QeAiFroY8p+qBfW6G1vvJ4Nz/+LDwk3AjSszzK3SBfCiE6QUftRg==", - "requires": { - "@react-leaflet/core": "^2.0.0" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" - }, - "react-leaflet": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.1.0.tgz", - "integrity": "sha512-i+V9pX5lywJ48O2+K3USeeTdYLIhxnLMweH+YLd/UPqVIj3uKzE3Q29bzt83PBtViyZmxDlulzC6uoR3JLiE9A==", - "requires": { - "@react-leaflet/core": "^2.1.0" - } - }, - "react-redux": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.4.tgz", - "integrity": "sha512-yMfQ7mX6bWuicz2fids6cR1YT59VTuT8MKyyE310wJQlINKENCeT1UcPdEiX6znI5tF8zXyJ/VYvDgeGuaaNwQ==", - "requires": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "dependencies": { - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - } - } - }, - "react-refresh": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", - "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", - "dev": true - }, - "react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dev": true, - "requires": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "fsevents": "^2.3.2", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - } - }, - "read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "graceful-fs": "^4.1.2", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "dev": true, - "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "recursive-readdir": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", - "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", - "dev": true, - "requires": { - "minimatch": "^3.0.5" - } - }, - "redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "requires": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - } - }, - "redux": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", - "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, - "redux-logger": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz", - "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=", - "requires": { - "deep-diff": "^0.3.5" - } - }, - "redux-thunk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "requires": {} - }, - "reftools": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.9.tgz", - "integrity": "sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==", - "dev": true - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-parser": { - "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "functions-have-names": "^1.2.2" - } - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true - }, - "renderkid": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", - "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^6.0.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "reselect": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz", - "integrity": "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==" - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resolve-protobuf-schema": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", - "peer": true, - "requires": { - "protocol-buffers-schema": "^3.3.1" - } - }, - "resolve-url-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", - "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", - "dev": true, - "requires": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^7.0.35", - "source-map": "0.6.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", - "dev": true - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", - "dev": true - }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "optional": true, - "requires": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "optional": true - } - } - }, - "rollup": { - "version": "2.68.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.68.0.tgz", - "integrity": "sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==", - "dev": true, - "requires": { - "fsevents": "~2.3.2" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "peer": true - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sanitize.css": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", - "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==", - "dev": true - }, - "sass-loader": { - "version": "12.6.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", - "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", - "dev": true, - "requires": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "requires": { - "loose-envify": "^1.1.0" - } - }, - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", - "dev": true, - "requires": { - "node-forge": "^1.2.0" - } - }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "dev": true, - "optional": true - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "optional": true, - "requires": { - "type-fest": "^0.13.1" - }, - "dependencies": { - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "optional": true - } - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - } - }, - "set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==", - "dev": true - }, - "should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dev": true, - "requires": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dev": true, - "requires": { - "should-type": "^1.4.0" - } - }, - "should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha512-hZ58adtulAk0gKtua7QxevgUaXTTXxIi8t41L3zo9AHvjXO1/7sdLECuHeIN2SRtYXpNkmhoUP2pdeWgricQ+Q==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha512-MdAsTu3n25yDbIe1NeN69G4n6mUnJGtSJHygX3+oN0ZbO3DTiATnf7XnYJdGT42JCXurTb1JI0qOBR65shvhPQ==", - "dev": true - }, - "should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dev": true, - "requires": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", - "dev": true - }, - "sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, - "source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - } - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "requires": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==", - "dev": true - }, - "spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true - }, - "spdx-satisfies": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz", - "integrity": "sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA==", - "dev": true, - "requires": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - } - }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true - }, - "stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - } - } - }, - "stackframe": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.1.tgz", - "integrity": "sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg==", - "dev": true - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "strict-event-emitter": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.4.6.tgz", - "integrity": "sha512-12KWeb+wixJohmnwNFerbyiBrAlq5qJLwIt38etRtKtmmHyDSoGlIqFE9wx+4IwG0aDjI7GV8tc8ZccjWZZtTg==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-natural-compare": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", - "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - } - } - }, - "string.prototype.matchall": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", - "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.1", - "side-channel": "^1.0.4" - } - }, - "string.prototype.trimend": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", - "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", - "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.19.5" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dev": true, - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", - "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "requires": { - "min-indent": "^1.0.0" - } - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "style-loader": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", - "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", - "dev": true, - "requires": {} - }, - "stylehacks": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.3.tgz", - "integrity": "sha512-ENcUdpf4yO0E1rubu8rkxI+JGQk4CgjchynZ4bDBJDfqdy+uhTRSWb8/F3Jtu+Bw5MW45Po3/aQGeIyyxgQtxg==", - "dev": true, - "requires": { - "browserslist": "^4.16.6", - "postcss-selector-parser": "^6.0.4" - } - }, - "sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, - "requires": { - "debug": "^4.1.0" - } - }, - "supercluster": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-7.1.5.tgz", - "integrity": "sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==", - "peer": true, - "requires": { - "kdbush": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-hyperlinks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", - "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "svg-parser": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", - "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", - "dev": true - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "dev": true - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dev": true, - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - }, - "dependencies": { - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - } - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - } - } - }, - "swagger2openapi": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", - "integrity": "sha512-upi/0ZGkYgEcLeGieoz8gT74oWHA0E7JivX7aN9mAf+Tc7BQoRBvnIGHoPDw+f9TXTW4s6kGYCZJtauP6OYp7g==", - "dev": true, - "requires": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.6", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.8", - "reftools": "^1.1.9", - "yaml": "^1.10.0", - "yargs": "^17.0.1" - }, - "dependencies": { - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "yargs": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", - "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "tailwindcss": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.23.tgz", - "integrity": "sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==", - "dev": true, - "requires": { - "arg": "^5.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.5.3", - "color-name": "^1.1.4", - "cosmiconfig": "^7.0.1", - "detective": "^5.2.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.11", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "normalize-path": "^3.0.0", - "object-hash": "^2.2.0", - "postcss": "^8.4.6", - "postcss-js": "^4.0.0", - "postcss-load-config": "^3.1.0", - "postcss-nested": "5.0.6", - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0", - "quick-lru": "^5.1.1", - "resolve": "^1.22.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "temp-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", - "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", - "dev": true - }, - "tempy": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", - "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "temp-dir": "^2.0.0", - "type-fest": "^0.16.0", - "unique-string": "^2.0.0" - }, - "dependencies": { - "type-fest": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", - "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", - "dev": true - } - } - }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, - "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "requires": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", - "dev": true - }, - "tiny-binary-search": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tiny-binary-search/-/tiny-binary-search-1.0.3.tgz", - "integrity": "sha512-STSHX/L5nI9WTLv6wrzJbAPbO7OIISX83KFBh2GVbX1Uz/vgZOU/ANn/8iV6t35yMTpoPzzO+3OQid3mifE0CA==" - }, - "tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==", - "peer": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } - } - }, - "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "treeify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", - "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", - "dev": true - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", - "dev": true - }, - "ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - } - } - }, - "tsconfig-paths": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - } - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true - }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", - "dev": true - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} - }, - "util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "vt-pbf": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/vt-pbf/-/vt-pbf-3.1.3.tgz", - "integrity": "sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==", - "peer": true, - "requires": { - "@mapbox/point-geometry": "0.1.0", - "@mapbox/vector-tile": "^1.3.1", - "pbf": "^3.2.1" - } - }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, - "wait-on": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz", - "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==", - "dev": true, - "requires": { - "axios": "^0.25.0", - "joi": "^17.6.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rxjs": "^7.5.4" - }, - "dependencies": { - "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", - "dev": true, - "requires": { - "follow-redirects": "^1.14.7" - } - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "dev": true, - "requires": { - "@zxing/text-encoding": "0.9.0", - "util": "^0.12.3" - } - }, - "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true - }, - "webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - } - } - }, - "webpack-dev-middleware": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz", - "integrity": "sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==", - "dev": true, - "requires": { - "colorette": "^2.0.10", - "memfs": "^3.4.1", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - } - } - }, - "webpack-dev-server": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz", - "integrity": "sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A==", - "dev": true, - "requires": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" - }, - "dependencies": { - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "schema-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.8.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.0.0" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "dev": true, - "requires": {} - } - } - }, - "webpack-manifest-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", - "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", - "dev": true, - "requires": { - "tapable": "^2.0.0", - "webpack-sources": "^2.2.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "webpack-sources": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", - "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - } - } - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, - "whatwg-fetch": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", - "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==", - "dev": true - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", - "dev": true - }, - "workbox-background-sync": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.5.0.tgz", - "integrity": "sha512-rrekt/gt6qOIZsisj6QZfmAFPAnocq1Z603zAjt+qHmeXY8DLPOklVtvrXSaHoHH3qIjUq3SQY5s2x240iTIKw==", - "dev": true, - "requires": { - "idb": "^6.1.4", - "workbox-core": "6.5.0" - } - }, - "workbox-broadcast-update": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.5.0.tgz", - "integrity": "sha512-JC97c7tYqoGWcCfbKO9KHG6lkU+WhXCnDB2j1oFWEiv53nUHy3yjPpzMmAGNLD9oV5lInO15n6V18HfwgkhISw==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-build": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.5.0.tgz", - "integrity": "sha512-da0/1b6//P9+ts7ofcIKcMVPyN6suJvjJASXokF7DsqvUmgRBPcCVV4KCy8QWjgfcz7mzuTpkSbdVHcPFJ/p0A==", - "dev": true, - "requires": { - "@apideck/better-ajv-errors": "^0.3.1", - "@babel/core": "^7.11.1", - "@babel/preset-env": "^7.11.0", - "@babel/runtime": "^7.11.2", - "@rollup/plugin-babel": "^5.2.0", - "@rollup/plugin-node-resolve": "^11.2.1", - "@rollup/plugin-replace": "^2.4.1", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", - "ajv": "^8.6.0", - "common-tags": "^1.8.0", - "fast-json-stable-stringify": "^2.1.0", - "fs-extra": "^9.0.1", - "glob": "^7.1.6", - "lodash": "^4.17.20", - "pretty-bytes": "^5.3.0", - "rollup": "^2.43.1", - "rollup-plugin-terser": "^7.0.0", - "source-map": "^0.8.0-beta.0", - "stringify-object": "^3.3.0", - "strip-comments": "^2.0.1", - "tempy": "^0.6.0", - "upath": "^1.2.0", - "workbox-background-sync": "6.5.0", - "workbox-broadcast-update": "6.5.0", - "workbox-cacheable-response": "6.5.0", - "workbox-core": "6.5.0", - "workbox-expiration": "6.5.0", - "workbox-google-analytics": "6.5.0", - "workbox-navigation-preload": "6.5.0", - "workbox-precaching": "6.5.0", - "workbox-range-requests": "6.5.0", - "workbox-recipes": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0", - "workbox-streams": "6.5.0", - "workbox-sw": "6.5.0", - "workbox-window": "6.5.0" - }, - "dependencies": { - "@apideck/better-ajv-errors": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.3.tgz", - "integrity": "sha512-9o+HO2MbJhJHjDYZaDxJmSDckvDpiuItEsrIShV0DXeCshXWRHhqYyU/PKHMkuClOmFnZhRd6wzv4vpDu/dRKg==", - "dev": true, - "requires": { - "json-schema": "^0.4.0", - "jsonpointer": "^5.0.0", - "leven": "^3.1.0" - } - }, - "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "workbox-cacheable-response": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.5.0.tgz", - "integrity": "sha512-sqAtWAiBwWvI8HG/2Do7BeKPhHuUczt22ORkAjkH9DfTq9LuWRFd6T4HAMqX5G8F1gM9XA2UPlxRrEeSpFIz/A==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-core": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.0.tgz", - "integrity": "sha512-5SPwNipUzYBhrneLVT02JFA0fw3LG82jFAN/G2NzxkIW10t4MVZuML2nU94bbkgjq25u0fkY8+4JXzMfHgxEWQ==", - "dev": true - }, - "workbox-expiration": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.5.0.tgz", - "integrity": "sha512-y3WRkKRy/gMuZZNkrLFahjY0QZtLoq+QfhTbVAsOGHVg1CCtnNbeFAnEidQs7UisI2BK76VqQPvM7hEOFyZ92A==", - "dev": true, - "requires": { - "idb": "^6.1.4", - "workbox-core": "6.5.0" - } - }, - "workbox-google-analytics": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.5.0.tgz", - "integrity": "sha512-CHHh55wMNCc/BV1URrzEM2Zjgf6g2CV6QpAAc1pBRqaLY5755PeQZbp3o8KbJEM7YsC9mIBeQVsOkSKkGS30bg==", - "dev": true, - "requires": { - "workbox-background-sync": "6.5.0", - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "workbox-navigation-preload": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.5.0.tgz", - "integrity": "sha512-ktrRQzXJ0zFy0puOtCa49wE3BSBGUB8KRMot3tEieikCkSO0wMLmiCb9GwTVvNMJLl0THRlsdFoI93si04nTxA==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-precaching": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.5.0.tgz", - "integrity": "sha512-IVLzgHx38T6LphJyEOltd7XAvpDi73p85uCT2ZtT1HHg9FAYC49a+5iHUVOnqye73fLW20eiAMFcnehGxz9RWg==", - "dev": true, - "requires": { - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "workbox-range-requests": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.5.0.tgz", - "integrity": "sha512-+qTELdGZE5rOjuv+ifFrfRDN8Uvzpbm5Fal7qSUqB1V1DLCMxPwHCj6mWwQBRKBpW7G09kAwewH7zA3Asjkf/Q==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-recipes": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.5.0.tgz", - "integrity": "sha512-7hWZAIcXmvr31NwYSWaQIrnThCH/Dx9+eYv/YdkpUeWIXRiHRkYvP1FdiHItbLSjL4Y6K7cy2Y9y5lGCkgaE4w==", - "dev": true, - "requires": { - "workbox-cacheable-response": "6.5.0", - "workbox-core": "6.5.0", - "workbox-expiration": "6.5.0", - "workbox-precaching": "6.5.0", - "workbox-routing": "6.5.0", - "workbox-strategies": "6.5.0" - } - }, - "workbox-routing": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.0.tgz", - "integrity": "sha512-w1A9OVa/yYStu9ds0Dj+TC6zOAoskKlczf+wZI5mrM9nFCt/KOMQiFp1/41DMFPrrN/8KlZTS3Cel/Ttutw93Q==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-strategies": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.0.tgz", - "integrity": "sha512-Ngnwo+tfGw4uKSlTz3h1fYKb/lCV7SDI/dtTb8VaJzRl0N9XssloDGYERBmF6BN/DV/x3bnRsshfobnKI/3z0g==", - "dev": true, - "requires": { - "workbox-core": "6.5.0" - } - }, - "workbox-streams": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.5.0.tgz", - "integrity": "sha512-ZbeaZINkju4x45P9DFyRbOYInE+dyNAJIelflz4f9AOAdm+zZUJCooU4MdfsedVhHiTIA6pCD/3jCmW1XbvlbA==", - "dev": true, - "requires": { - "workbox-core": "6.5.0", - "workbox-routing": "6.5.0" - } - }, - "workbox-sw": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.0.tgz", - "integrity": "sha512-uPGJ9Yost4yabnCko/IuhouquoQKrWOEqLq7L/xVYtltWe4+J8Hw8iPCVtxvXQ26hffd7MaFWUAN83j2ZWbxRg==", - "dev": true - }, - "workbox-webpack-plugin": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.0.tgz", - "integrity": "sha512-wy4uCBJELNfJVf2b4Tg3mjJQySq/aReWv4Q1RxQweJkY9ihq7DOGA3wLlXvoauek+MX/SuQfS3it+eXIfHKjvg==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "^2.1.0", - "pretty-bytes": "^5.4.1", - "upath": "^1.2.0", - "webpack-sources": "^1.4.3", - "workbox-build": "6.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - } - } - }, - "workbox-window": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.0.tgz", - "integrity": "sha512-DOrhiTnWup/CsNstO2uvfdKM4kdStgHd31xGGvBcoCE3Are3DRcy5s3zz3PedcAR1AKskQj3BXz0UhzQiOq8nA==", - "dev": true, - "requires": { - "@types/trusted-types": "^2.0.2", - "workbox-core": "6.5.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/client/package.json b/client/package.json deleted file mode 100644 index fcf82606c..000000000 --- a/client/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "liberation-client", - "version": "0.1.0", - "private": true, - "main": "main.js", - "license": "LGPL-3.0-or-later", - "homepage": ".", - "dependencies": { - "@reduxjs/toolkit": "^1.8.5", - "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^14.4.3", - "@types/jest": "^29.1.2", - "@types/node": "^18.8.3", - "@types/react": "^18.0.21", - "@types/react-dom": "^18.0.6", - "@types/react-redux": "^7.1.24", - "axios": "^1.6.0", - "electron-window-state": "^5.0.3", - "esri-leaflet": "^3.0.8", - "leaflet": "^1.9.2", - "leaflet-ruler": "^1.0.0", - "milsymbol": "^2.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-esri-leaflet": "^2.0.1", - "react-leaflet": "^4.1.0", - "react-redux": "^8.0.4", - "redux-logger": "^3.0.6", - "typescript": "~4.8.4" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build && generate-license-file --input package.json --output build/NOTICE", - "regenerate-api": "rtk-query-codegen-openapi ./openapi-config.ts", - "lint": "eslint src", - "prepare": "eslint src && license-checker --onlyAllow \"MIT;Apache-2.0;CC0-1.0;BSD-3-Clause;ISC;Custom: https://github.com/tmcw/jsonlint;BSD-2-Clause;Hippocratic-2.1;BSD*;WTFPL\" --excludePrivatePackages --production", - "test": "react-scripts test", - "eject": "react-scripts eject", - "electron": "wait-on tcp:3000 && electron ." - }, - "eslintConfig": { - "extends": "react-app" - }, - "eslintIgnore": [ - "leaflet-ruler.d.ts" - ], - "prettier": { - "endOfLine": "auto" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "devDependencies": { - "@rtk-query/codegen-openapi": "^1.0.0", - "@trivago/prettier-plugin-sort-imports": "^4.2.1", - "@types/leaflet": "^1.8.0", - "@types/redux-logger": "^3.0.9", - "@types/websocket": "^1.0.5", - "electron": "^22.3.25", - "electron-is-dev": "^2.0.0", - "generate-license-file": "^2.0.0", - "jest-transform-stub": "^2.0.0", - "license-checker": "^25.0.1", - "msw": "^1.2.2", - "react-scripts": "5.0.1", - "ts-node": "^10.9.1", - "wait-on": "^6.0.1" - }, - "jest": { - "transformIgnorePatterns": [ - "node_modules/(?!(@?react-leaflet|axios)/)" - ], - "moduleNameMapper": { - ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub" - } - } -} diff --git a/client/public/favicon.ico b/client/public/favicon.ico deleted file mode 100644 index 354202a4e..000000000 Binary files a/client/public/favicon.ico and /dev/null differ diff --git a/client/public/index.html b/client/public/index.html deleted file mode 100644 index 1dbdca65e..000000000 --- a/client/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - React Redux App - - - -
- - - diff --git a/client/public/logo192.png b/client/public/logo192.png deleted file mode 100644 index 33624109c..000000000 Binary files a/client/public/logo192.png and /dev/null differ diff --git a/client/public/logo512.png b/client/public/logo512.png deleted file mode 100644 index b3516222f..000000000 Binary files a/client/public/logo512.png and /dev/null differ diff --git a/client/public/manifest.json b/client/public/manifest.json deleted file mode 100644 index 080d6c77a..000000000 --- a/client/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "React App", - "name": "Create React App Sample", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/client/public/robots.txt b/client/public/robots.txt deleted file mode 100644 index e9e57dc4d..000000000 --- a/client/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/client/src/App.test.tsx b/client/src/App.test.tsx deleted file mode 100644 index 461ef5037..000000000 --- a/client/src/App.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import App from "./App"; -import { setupStore } from "./app/store"; -import { render } from "@testing-library/react"; -import { Provider } from "react-redux"; - -test("app renders", () => { - render( - - - - ); -}); diff --git a/client/src/App.tsx b/client/src/App.tsx deleted file mode 100644 index a0852c87a..000000000 --- a/client/src/App.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import LiberationMap from "./components/liberationmap"; -import useEventStream from "./hooks/useEventSteam"; -import useInitialGameState from "./hooks/useInitialGameState"; - -function App() { - useInitialGameState(); - useEventStream(); - - return ( -
- -
- ); -} - -export default App; diff --git a/client/src/api/_liberationApi.ts b/client/src/api/_liberationApi.ts deleted file mode 100644 index 00e4218f9..000000000 --- a/client/src/api/_liberationApi.ts +++ /dev/null @@ -1,504 +0,0 @@ -import { baseApi as api } from "./baseApi"; - -const injectedRtkApi = api.injectEndpoints({ - endpoints: (build) => ({ - listControlPoints: build.query< - ListControlPointsApiResponse, - ListControlPointsApiArg - >({ - query: () => ({ url: `/control-points/` }), - }), - getControlPointById: build.query< - GetControlPointByIdApiResponse, - GetControlPointByIdApiArg - >({ - query: (queryArg) => ({ url: `/control-points/${queryArg.cpId}` }), - }), - controlPointDestinationInRange: build.query< - ControlPointDestinationInRangeApiResponse, - ControlPointDestinationInRangeApiArg - >({ - query: (queryArg) => ({ - url: `/control-points/${queryArg.cpId}/destination-in-range`, - params: { lat: queryArg.lat, lng: queryArg.lng }, - }), - }), - setControlPointDestination: build.mutation< - SetControlPointDestinationApiResponse, - SetControlPointDestinationApiArg - >({ - query: (queryArg) => ({ - url: `/control-points/${queryArg.cpId}/destination`, - method: "PUT", - body: queryArg.body, - }), - }), - clearControlPointDestination: build.mutation< - ClearControlPointDestinationApiResponse, - ClearControlPointDestinationApiArg - >({ - query: (queryArg) => ({ - url: `/control-points/${queryArg.cpId}/cancel-travel`, - method: "PUT", - }), - }), - getDebugHoldZones: build.query< - GetDebugHoldZonesApiResponse, - GetDebugHoldZonesApiArg - >({ - query: (queryArg) => ({ - url: `/debug/waypoint-geometries/hold/${queryArg.flightId}`, - }), - }), - getDebugJoinZones: build.query< - GetDebugJoinZonesApiResponse, - GetDebugJoinZonesApiArg - >({ - query: (queryArg) => ({ - url: `/debug/waypoint-geometries/join/${queryArg.flightId}`, - }), - }), - listFlights: build.query({ - query: (queryArg) => ({ - url: `/flights/`, - params: { with_waypoints: queryArg.withWaypoints }, - }), - }), - getFlightById: build.query({ - query: (queryArg) => ({ - url: `/flights/${queryArg.flightId}`, - params: { with_waypoints: queryArg.withWaypoints }, - }), - }), - getCommitBoundaryForFlight: build.query< - GetCommitBoundaryForFlightApiResponse, - GetCommitBoundaryForFlightApiArg - >({ - query: (queryArg) => ({ - url: `/flights/${queryArg.flightId}/commit-boundary`, - }), - }), - listFrontLines: build.query< - ListFrontLinesApiResponse, - ListFrontLinesApiArg - >({ - query: () => ({ url: `/front-lines/` }), - }), - getFrontLineById: build.query< - GetFrontLineByIdApiResponse, - GetFrontLineByIdApiArg - >({ - query: (queryArg) => ({ url: `/front-lines/${queryArg.frontLineId}` }), - }), - getGameState: build.query({ - query: () => ({ url: `/game/` }), - }), - getTerrainZones: build.query< - GetTerrainZonesApiResponse, - GetTerrainZonesApiArg - >({ - query: () => ({ url: `/map-zones/terrain` }), - }), - listUnculledZones: build.query< - ListUnculledZonesApiResponse, - ListUnculledZonesApiArg - >({ - query: () => ({ url: `/map-zones/unculled` }), - }), - getThreatZones: build.query< - GetThreatZonesApiResponse, - GetThreatZonesApiArg - >({ - query: () => ({ url: `/map-zones/threats` }), - }), - getNavmesh: build.query({ - query: (queryArg) => ({ - url: `/navmesh/`, - params: { for_player: queryArg.forPlayer }, - }), - }), - openNewFrontLinePackageDialog: build.mutation< - OpenNewFrontLinePackageDialogApiResponse, - OpenNewFrontLinePackageDialogApiArg - >({ - query: (queryArg) => ({ - url: `/qt/create-package/front-line/${queryArg.frontLineId}`, - method: "POST", - }), - }), - openNewTgoPackageDialog: build.mutation< - OpenNewTgoPackageDialogApiResponse, - OpenNewTgoPackageDialogApiArg - >({ - query: (queryArg) => ({ - url: `/qt/create-package/tgo/${queryArg.tgoId}`, - method: "POST", - }), - }), - openTgoInfoDialog: build.mutation< - OpenTgoInfoDialogApiResponse, - OpenTgoInfoDialogApiArg - >({ - query: (queryArg) => ({ - url: `/qt/info/tgo/${queryArg.tgoId}`, - method: "POST", - }), - }), - openNewControlPointPackageDialog: build.mutation< - OpenNewControlPointPackageDialogApiResponse, - OpenNewControlPointPackageDialogApiArg - >({ - query: (queryArg) => ({ - url: `/qt/create-package/control-point/${queryArg.cpId}`, - method: "POST", - }), - }), - openControlPointInfoDialog: build.mutation< - OpenControlPointInfoDialogApiResponse, - OpenControlPointInfoDialogApiArg - >({ - query: (queryArg) => ({ - url: `/qt/info/control-point/${queryArg.cpId}`, - method: "POST", - }), - }), - listSupplyRoutes: build.query< - ListSupplyRoutesApiResponse, - ListSupplyRoutesApiArg - >({ - query: () => ({ url: `/supply-routes/` }), - }), - listTgos: build.query({ - query: () => ({ url: `/tgos/` }), - }), - getTgoById: build.query({ - query: (queryArg) => ({ url: `/tgos/${queryArg.tgoId}` }), - }), - listAllWaypointsForFlight: build.query< - ListAllWaypointsForFlightApiResponse, - ListAllWaypointsForFlightApiArg - >({ - query: (queryArg) => ({ url: `/waypoints/${queryArg.flightId}` }), - }), - setWaypointPosition: build.mutation< - SetWaypointPositionApiResponse, - SetWaypointPositionApiArg - >({ - query: (queryArg) => ({ - url: `/waypoints/${queryArg.flightId}/${queryArg.waypointIdx}/position`, - method: "POST", - body: queryArg.leafletPoint, - }), - }), - getIadsNetwork: build.query< - GetIadsNetworkApiResponse, - GetIadsNetworkApiArg - >({ - query: () => ({ url: `/iads-network/` }), - }), - getIadsConnectionsForTgo: build.query< - GetIadsConnectionsForTgoApiResponse, - GetIadsConnectionsForTgoApiArg - >({ - query: (queryArg) => ({ url: `/iads-network/for-tgo/${queryArg.tgoId}` }), - }), - }), - overrideExisting: false, -}); -export { injectedRtkApi as _liberationApi }; -export type ListControlPointsApiResponse = - /** status 200 Successful Response */ ControlPoint[]; -export type ListControlPointsApiArg = void; -export type GetControlPointByIdApiResponse = - /** status 200 Successful Response */ ControlPoint; -export type GetControlPointByIdApiArg = { - cpId: string; -}; -export type ControlPointDestinationInRangeApiResponse = - /** status 200 Successful Response */ boolean; -export type ControlPointDestinationInRangeApiArg = { - cpId: string; - lat: number; - lng: number; -}; -export type SetControlPointDestinationApiResponse = - /** status 204 Successful Response */ undefined; -export type SetControlPointDestinationApiArg = { - cpId: string; - body: LatLng; -}; -export type ClearControlPointDestinationApiResponse = - /** status 204 Successful Response */ undefined; -export type ClearControlPointDestinationApiArg = { - cpId: string; -}; -export type GetDebugHoldZonesApiResponse = - /** status 200 Successful Response */ HoldZones; -export type GetDebugHoldZonesApiArg = { - flightId: string; -}; -export type GetDebugJoinZonesApiResponse = - /** status 200 Successful Response */ JoinZones; -export type GetDebugJoinZonesApiArg = { - flightId: string; -}; -export type ListFlightsApiResponse = - /** status 200 Successful Response */ Flight[]; -export type ListFlightsApiArg = { - withWaypoints?: boolean; -}; -export type GetFlightByIdApiResponse = - /** status 200 Successful Response */ Flight; -export type GetFlightByIdApiArg = { - flightId: string; - withWaypoints?: boolean; -}; -export type GetCommitBoundaryForFlightApiResponse = - /** status 200 Successful Response */ LatLng[][]; -export type GetCommitBoundaryForFlightApiArg = { - flightId: string; -}; -export type ListFrontLinesApiResponse = - /** status 200 Successful Response */ FrontLine[]; -export type ListFrontLinesApiArg = void; -export type GetFrontLineByIdApiResponse = - /** status 200 Successful Response */ FrontLine; -export type GetFrontLineByIdApiArg = { - frontLineId: string; -}; -export type GetGameStateApiResponse = - /** status 200 Successful Response */ Game; -export type GetGameStateApiArg = void; -export type GetTerrainZonesApiResponse = - /** status 200 Successful Response */ MapZones; -export type GetTerrainZonesApiArg = void; -export type ListUnculledZonesApiResponse = - /** status 200 Successful Response */ UnculledZone[]; -export type ListUnculledZonesApiArg = void; -export type GetThreatZonesApiResponse = - /** status 200 Successful Response */ ThreatZoneContainer; -export type GetThreatZonesApiArg = void; -export type GetNavmeshApiResponse = - /** status 200 Successful Response */ NavMesh; -export type GetNavmeshApiArg = { - forPlayer: boolean; -}; -export type OpenNewFrontLinePackageDialogApiResponse = - /** status 200 Successful Response */ any; -export type OpenNewFrontLinePackageDialogApiArg = { - frontLineId: string; -}; -export type OpenNewTgoPackageDialogApiResponse = - /** status 200 Successful Response */ any; -export type OpenNewTgoPackageDialogApiArg = { - tgoId: string; -}; -export type OpenTgoInfoDialogApiResponse = - /** status 200 Successful Response */ any; -export type OpenTgoInfoDialogApiArg = { - tgoId: string; -}; -export type OpenNewControlPointPackageDialogApiResponse = - /** status 200 Successful Response */ any; -export type OpenNewControlPointPackageDialogApiArg = { - cpId: string; -}; -export type OpenControlPointInfoDialogApiResponse = - /** status 200 Successful Response */ any; -export type OpenControlPointInfoDialogApiArg = { - cpId: string; -}; -export type ListSupplyRoutesApiResponse = - /** status 200 Successful Response */ SupplyRoute[]; -export type ListSupplyRoutesApiArg = void; -export type ListTgosApiResponse = /** status 200 Successful Response */ Tgo[]; -export type ListTgosApiArg = void; -export type GetTgoByIdApiResponse = /** status 200 Successful Response */ Tgo; -export type GetTgoByIdApiArg = { - tgoId: string; -}; -export type ListAllWaypointsForFlightApiResponse = - /** status 200 Successful Response */ Waypoint[]; -export type ListAllWaypointsForFlightApiArg = { - flightId: string; -}; -export type SetWaypointPositionApiResponse = - /** status 204 Successful Response */ undefined; -export type SetWaypointPositionApiArg = { - flightId: string; - waypointIdx: number; - leafletPoint: LatLng; -}; -export type GetIadsNetworkApiResponse = - /** status 200 Successful Response */ IadsNetwork; -export type GetIadsNetworkApiArg = void; -export type GetIadsConnectionsForTgoApiResponse = - /** status 200 Successful Response */ IadsConnection[]; -export type GetIadsConnectionsForTgoApiArg = { - tgoId: string; -}; -export type LatLng = { - lat: number; - lng: number; -}; -export type ControlPoint = { - id: string; - name: string; - blue: boolean; - position: LatLng; - mobile: boolean; - destination?: LatLng; - sidc: string; -}; -export type ValidationError = { - loc: (string | number)[]; - msg: string; - type: string; -}; -export type HttpValidationError = { - detail?: ValidationError[]; -}; -export type HoldZones = { - homeBubble: LatLng[][]; - targetBubble: LatLng[][]; - joinBubble: LatLng[][]; - excludedZones: LatLng[][][]; - permissibleZones: LatLng[][][]; - preferredLines: LatLng[][]; -}; -export type JoinZones = { - homeBubble: LatLng[][]; - targetBubble: LatLng[][]; - ipBubble: LatLng[][]; - excludedZones: LatLng[][][]; - permissibleZones: LatLng[][][]; - preferredLines: LatLng[][]; -}; -export type Waypoint = { - name: string; - position: LatLng; - altitude_ft: number; - altitude_reference: string; - is_movable: boolean; - should_mark: boolean; - include_in_path: boolean; - timing: string; -}; -export type Flight = { - id: string; - blue: boolean; - position?: LatLng; - sidc: string; - waypoints?: Waypoint[]; -}; -export type FrontLine = { - id: string; - extents: LatLng[]; -}; -export type Tgo = { - id: string; - name: string; - control_point_name: string; - category: string; - blue: boolean; - position: LatLng; - units: string[]; - threat_ranges: number[]; - detection_ranges: number[]; - dead: boolean; - sidc: string; -}; -export type SupplyRoute = { - id: string; - points: LatLng[]; - front_active: boolean; - is_sea: boolean; - blue: boolean; - active_transports: string[]; -}; -export type IadsConnection = { - id: string; - points: LatLng[]; - node: string; - connected: string; - active: boolean; - blue: boolean; - is_power: boolean; -}; -export type IadsNetwork = { - advanced: boolean; - connections: IadsConnection[]; -}; -export type ThreatZones = { - full: LatLng[][][]; - aircraft: LatLng[][][]; - air_defenses: LatLng[][][]; - radar_sams: LatLng[][][]; -}; -export type ThreatZoneContainer = { - blue: ThreatZones; - red: ThreatZones; -}; -export type NavMeshPoly = { - poly: LatLng[][]; - threatened: boolean; -}; -export type NavMesh = { - polys: NavMeshPoly[]; -}; -export type NavMeshes = { - blue: NavMesh; - red: NavMesh; -}; -export type UnculledZone = { - position: LatLng; - radius: number; -}; -export type Game = { - control_points: ControlPoint[]; - tgos: Tgo[]; - supply_routes: SupplyRoute[]; - front_lines: FrontLine[]; - flights: Flight[]; - iads_network: IadsNetwork; - threat_zones: ThreatZoneContainer; - navmeshes: NavMeshes; - map_center?: LatLng; - unculled_zones: UnculledZone[]; -}; -export type MapZones = { - inclusion: LatLng[][][]; - exclusion: LatLng[][][]; - sea: LatLng[][][]; -}; -export const { - useListControlPointsQuery, - useGetControlPointByIdQuery, - useControlPointDestinationInRangeQuery, - useSetControlPointDestinationMutation, - useClearControlPointDestinationMutation, - useGetDebugHoldZonesQuery, - useGetDebugJoinZonesQuery, - useListFlightsQuery, - useGetFlightByIdQuery, - useGetCommitBoundaryForFlightQuery, - useListFrontLinesQuery, - useGetFrontLineByIdQuery, - useGetGameStateQuery, - useGetTerrainZonesQuery, - useListUnculledZonesQuery, - useGetThreatZonesQuery, - useGetNavmeshQuery, - useOpenNewFrontLinePackageDialogMutation, - useOpenNewTgoPackageDialogMutation, - useOpenTgoInfoDialogMutation, - useOpenNewControlPointPackageDialogMutation, - useOpenControlPointInfoDialogMutation, - useListSupplyRoutesQuery, - useListTgosQuery, - useGetTgoByIdQuery, - useListAllWaypointsForFlightQuery, - useSetWaypointPositionMutation, - useGetIadsNetworkQuery, - useGetIadsConnectionsForTgoQuery, -} = injectedRtkApi; diff --git a/client/src/api/actions.ts b/client/src/api/actions.ts deleted file mode 100644 index 3edbaeef8..000000000 --- a/client/src/api/actions.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Game } from "./liberationApi"; -import { createAction } from "@reduxjs/toolkit"; - -export const gameLoaded = createAction("game/loaded"); -export const gameUnloaded = createAction("game/unloaded"); diff --git a/client/src/api/backend.ts b/client/src/api/backend.ts deleted file mode 100644 index eb05de506..000000000 --- a/client/src/api/backend.ts +++ /dev/null @@ -1,18 +0,0 @@ -import axios from "axios"; - -const backendAddr = - new URL(window.location.toString()).searchParams.get("server") ?? - "[::1]:16880"; - -// MSW can't handle IPv6 URLs... -// https://github.com/mswjs/msw/issues/1388 -export const HTTP_URL = - process.env.NODE_ENV === "test" ? "" : `http://${backendAddr}/`; - -export const backend = axios.create({ - baseURL: HTTP_URL, -}); - -export const WEBSOCKET_URL = `ws://${backendAddr}/eventstream`; - -export default backend; diff --git a/client/src/api/baseApi.ts b/client/src/api/baseApi.ts deleted file mode 100644 index dd6931c47..000000000 --- a/client/src/api/baseApi.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { HTTP_URL } from "./backend"; -import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; - -export const baseApi = createApi({ - baseQuery: fetchBaseQuery({ baseUrl: HTTP_URL }), - endpoints: () => ({}), -}); diff --git a/client/src/api/combat.ts b/client/src/api/combat.ts deleted file mode 100644 index 23a1d4829..000000000 --- a/client/src/api/combat.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { LatLng } from "leaflet"; - -export default interface Combat { - id: string; - flight_position: LatLng | null; - target_positions: LatLng[] | null; - footprint: LatLng[][] | null; -} diff --git a/client/src/api/combatSlice.ts b/client/src/api/combatSlice.ts deleted file mode 100644 index 66d0ed707..000000000 --- a/client/src/api/combatSlice.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import Combat from "./combat"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface CombatState { - combat: { [key: string]: Combat }; -} - -const initialState: CombatState = { - combat: {}, -}; - -export const combatSlice = createSlice({ - name: "combat", - initialState, - reducers: { - newCombats: (state, action: PayloadAction) => { - for (const combat of action.payload) { - state.combat[combat.id] = combat; - } - }, - updateCombats: (state, action: PayloadAction) => { - for (const combat of action.payload) { - state.combat[combat.id] = combat; - } - }, - endCombats: (state, action: PayloadAction) => { - for (const cID of action.payload) { - delete state.combat[cID]; - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.combat = {}; - }); - builder.addCase(gameUnloaded, (state) => { - state.combat = {}; - }); - }, -}); - -export const { newCombats, updateCombats, endCombats } = - combatSlice.actions; - -export const selectCombat = (state: RootState) => state.combat; - -export default combatSlice.reducer; diff --git a/client/src/api/controlPointsSlice.ts b/client/src/api/controlPointsSlice.ts deleted file mode 100644 index a10c500d1..000000000 --- a/client/src/api/controlPointsSlice.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { ControlPoint } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface ControlPointsState { - controlPoints: { [key: string]: ControlPoint }; -} - -const initialState: ControlPointsState = { - controlPoints: {}, -}; - -export const controlPointsSlice = createSlice({ - name: "controlPoints", - initialState, - reducers: { - updateControlPoint: (state, action: PayloadAction) => { - for (const cp of action.payload) { - state.controlPoints[cp.id] = cp; - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.controlPoints = action.payload.control_points.reduce( - (acc: { [key: string]: ControlPoint }, curr) => { - acc[curr.id] = curr; - return acc; - }, - {} - ); - }); - builder.addCase(gameUnloaded, (state) => { - state.controlPoints = {}; - }); - }, -}); - -export const { updateControlPoint } = controlPointsSlice.actions; - -export const selectControlPoints = (state: RootState) => state.controlPoints; - -export default controlPointsSlice.reducer; diff --git a/client/src/api/eventstream.tsx b/client/src/api/eventstream.tsx deleted file mode 100644 index b67e78e7f..000000000 --- a/client/src/api/eventstream.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import { AppDispatch } from "../app/store"; -import { gameUnloaded } from "./actions"; -import Combat from "./combat"; -import { endCombats, newCombats, updateCombats } from "./combatSlice"; -import { updateControlPoint } from "./controlPointsSlice"; -import { - deselectFlight, - registerFlights, - selectFlight, - unregisterFlights, - updateFlights, - updateFlightPositions, -} from "./flightsSlice"; -import { - deleteFrontLine, - updateFrontLine, -} from "./frontLinesSlice"; -import reloadGameState from "./gamestate"; -import { - ControlPoint, - Flight, - FrontLine, - IadsConnection, - NavMesh, - Tgo, - ThreatZones, - UnculledZone, -} from "./liberationApi"; -import { navMeshUpdated } from "./navMeshSlice"; -import { updateTgo } from "./tgosSlice"; -import { threatZonesUpdated } from "./threatZonesSlice"; -import { unculledZonesUpdated } from "./unculledZonesSlice"; -import { LatLng } from "leaflet"; -import { updateIadsConnection, removeIadsConnection } from "./iadsNetworkSlice"; - -interface GameUpdateEvents { - updated_flight_positions: { [id: string]: LatLng }; - new_combats: Combat[]; - updated_combats: Combat[]; - ended_combats: string[]; - navmesh_updates: {blue: boolean, mesh: NavMesh}[]; - updated_unculled_zones: UnculledZone[]; - threat_zones_updated: {blue: boolean, zones: ThreatZones}[]; - new_flights: Flight[]; - updated_flights: Flight[]; - deleted_flights: string[]; - selected_flight: string | null; - deselected_flight: boolean; - updated_front_lines: FrontLine[]; - deleted_front_lines: string[]; - updated_tgos: Tgo[]; - updated_control_points: ControlPoint[]; - updated_iads: IadsConnection[]; - deleted_iads: string[]; - reset_on_map_center: LatLng | null; - game_unloaded: boolean; - new_turn: boolean; -} - -export const handleStreamedEvents = ( - dispatch: AppDispatch, - events: GameUpdateEvents -) => { - if (Object.keys(events.updated_flight_positions).length) { - dispatch( - updateFlightPositions(Object.entries(events.updated_flight_positions)) - ); - } - - if (events.new_combats.length > 0) { - dispatch(newCombats(events.new_combats)); - } - - if (events.updated_combats.length > 0) { - dispatch(updateCombats(events.updated_combats)); - } - - if (events.ended_combats.length > 0) { - dispatch(endCombats(events.ended_combats)); - } - - if (Object.keys(events.navmesh_updates).length > 0) { - dispatch(navMeshUpdated(events.navmesh_updates)); - } - - if (events.updated_unculled_zones.length > 0) { - dispatch(unculledZonesUpdated(events.updated_unculled_zones)); - } - - if (Object.keys(events.threat_zones_updated).length > 0) { - dispatch(threatZonesUpdated(events.threat_zones_updated)); - } - - if (events.new_flights.length > 0) { - dispatch(registerFlights(events.new_flights)); - } - - if (events.updated_flights.length > 0) { - dispatch(updateFlights(events.updated_flights)); - } - - if (events.deleted_flights.length > 0) { - dispatch(unregisterFlights(events.deleted_flights)); - } - - if (events.deselected_flight) { - dispatch(deselectFlight()); - } - - if (events.selected_flight != null) { - dispatch(selectFlight(events.selected_flight)); - } - - if (events.updated_front_lines.length > 0) { - dispatch(updateFrontLine(events.updated_front_lines)); - } - - if (events.deleted_front_lines.length > 0) { - dispatch(deleteFrontLine(events.deleted_front_lines)); - } - - if (events.updated_tgos.length > 0) { - dispatch(updateTgo(events.updated_tgos)); - } - - if (events.updated_control_points.length > 0) { - dispatch(updateControlPoint(events.updated_control_points)); - } - - if (events.deleted_iads.length > 0) { - dispatch(removeIadsConnection(events.deleted_iads)); - } - - if (events.updated_iads.length > 0) { - dispatch(updateIadsConnection(events.updated_iads)); - } - - if (events.reset_on_map_center != null) { - reloadGameState(dispatch); - } - - if (events.game_unloaded) { - dispatch(gameUnloaded()); - } - - if (events.new_turn) { - reloadGameState(dispatch, true); - } -}; diff --git a/client/src/api/flightsSlice.ts b/client/src/api/flightsSlice.ts deleted file mode 100644 index 2ff706e7a..000000000 --- a/client/src/api/flightsSlice.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { Flight } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; -import { LatLng } from "leaflet"; - -interface FlightsState { - flights: { [id: string]: Flight }; - selected: string | null; -} - -const initialState: FlightsState = { - flights: {}, - selected: null, -}; - -export const flightsSlice = createSlice({ - name: "flights", - initialState, - reducers: { - registerFlights: (state, action: PayloadAction) => { - for (const flight of action.payload) { - if (flight.id in state.flights) { - console.log(`Overriding flight with ID: ${flight.id}`); - } - state.flights[flight.id] = flight; - } - }, - unregisterFlights: (state, action: PayloadAction) => { - for (const id of action.payload) { - delete state.flights[id]; - } - }, - updateFlights: (state, action: PayloadAction) => { - for (const flight of action.payload) { - state.flights[flight.id] = flight; - } - }, - deselectFlight: (state) => { - state.selected = null; - }, - selectFlight: (state, action: PayloadAction) => { - state.selected = action.payload; - }, - updateFlightPositions: ( - state, - action: PayloadAction<[string, LatLng][]> - ) => { - for (const [id, position] of action.payload) { - state.flights[id].position = position; - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.selected = null; - state.flights = action.payload.flights.reduce( - (acc: { [key: string]: Flight }, curr) => { - acc[curr.id] = curr; - return acc; - }, - {} - ); - }); - builder.addCase(gameUnloaded, (state) => { - state.selected = null; - state.flights = {}; - }); - }, -}); - -export const { - registerFlights, - unregisterFlights, - updateFlights, - deselectFlight, - selectFlight, - updateFlightPositions, -} = flightsSlice.actions; - -export const selectFlights = (state: RootState) => state.flights; -export const selectSelectedFlightId = (state: RootState) => - state.flights.selected; -export const selectSelectedFlight = (state: RootState) => { - const id = state.flights.selected; - return id ? state.flights.flights[id] : null; -}; - -export default flightsSlice.reducer; diff --git a/client/src/api/frontLinesSlice.ts b/client/src/api/frontLinesSlice.ts deleted file mode 100644 index 832890d7c..000000000 --- a/client/src/api/frontLinesSlice.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { FrontLine } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface FrontLinesState { - fronts: { [key: string]: FrontLine }; -} - -const initialState: FrontLinesState = { - fronts: {}, -}; - -export const frontLinesSlice = createSlice({ - name: "frontLines", - initialState, - reducers: { - updateFrontLine: (state, action: PayloadAction) => { - for (const front of action.payload) { - state.fronts[front.id] = front; - } - }, - deleteFrontLine: (state, action: PayloadAction) => { - for (const uid of action.payload) { - delete state.fronts[uid]; - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.fronts = action.payload.front_lines.reduce( - (acc: { [key: string]: FrontLine }, curr) => { - acc[curr.id] = curr; - return acc; - }, - {} - ); - }); - builder.addCase(gameUnloaded, (state) => { - state.fronts = {}; - }); - }, -}); - -export const { updateFrontLine, deleteFrontLine } = - frontLinesSlice.actions; - -export const selectFrontLines = (state: RootState) => state.frontLines; - -export default frontLinesSlice.reducer; diff --git a/client/src/api/gamestate.ts b/client/src/api/gamestate.ts deleted file mode 100644 index 84937f0e1..000000000 --- a/client/src/api/gamestate.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AppDispatch } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import backend from "./backend"; -import { Game } from "./liberationApi"; - -export default function reloadGameState( - dispatch: AppDispatch, - ignoreRecenter: boolean = false -) { - backend - .get("/game") - .catch((error) => console.log(`Error fetching game state: ${error}`)) - .then((response) => { - if (response == null || response.data == null) { - dispatch(gameUnloaded()); - return; - } - const game = response.data as Game; - if (ignoreRecenter) { - game.map_center = undefined; - } - dispatch(gameLoaded(game)); - }); -} diff --git a/client/src/api/iadsNetworkSlice.ts b/client/src/api/iadsNetworkSlice.ts deleted file mode 100644 index f61fcff74..000000000 --- a/client/src/api/iadsNetworkSlice.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; -import { IadsConnection} from "./_liberationApi"; - -interface IadsNetworkState { - connections: {[key: string]: IadsConnection} -} - -const initialState: IadsNetworkState = { - connections: {}, -}; - -export const IadsNetworkSlice = createSlice({ - name: "iadsNetwork", - initialState, - reducers: { - updateIadsConnection: (state, action: PayloadAction) => { - for (const connection of action.payload) { - state.connections[connection.id] = connection - } - }, - removeIadsConnection: (state, action: PayloadAction) => { - for (const cID of action.payload) { - delete state.connections[cID]; - } - } - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.connections = action.payload.iads_network.connections.reduce( - (acc: { [key: string]: IadsConnection }, curr) => { - acc[curr.id] = curr; - return acc; - }, - {} - ); - }); - builder.addCase(gameUnloaded, (state) => { - state.connections = {}; - }); - }, -}); - -export const { updateIadsConnection, removeIadsConnection } = IadsNetworkSlice.actions; - -export const selectIadsNetwork = (state: RootState) => state.iadsNetwork; - -export default IadsNetworkSlice.reducer; diff --git a/client/src/api/liberationApi.ts b/client/src/api/liberationApi.ts deleted file mode 100644 index 165e0d2bc..000000000 --- a/client/src/api/liberationApi.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { _liberationApi } from "./_liberationApi"; - -// See https://redux-toolkit.js.org/rtk-query/usage/automated-refetching for an -// explanation of tag behavior. - -export enum Tags { - FLIGHT_PLAN = "FlightPlan", -} - -const LIST_ID = "LIST"; - -function providesList( - resultsWithIds: R | undefined, - tagType: T -) { - return resultsWithIds - ? [ - { type: tagType, id: LIST_ID }, - ...resultsWithIds.map(({ id }) => ({ type: tagType, id })), - ] - : [{ type: tagType, id: LIST_ID }]; -} - -export const liberationApi = _liberationApi.enhanceEndpoints({ - addTagTypes: Object.values(Tags), - endpoints: { - // /debug/waypoint-geometries - getDebugHoldZones: { - providesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - getDebugJoinZones: { - providesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - // /flights/ - getCommitBoundaryForFlight: { - providesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - getFlightById: { - providesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - listFlights: { - providesTags: (result) => providesList(result, Tags.FLIGHT_PLAN), - }, - // /waypoints/ - listAllWaypointsForFlight: { - providesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - setWaypointPosition: { - invalidatesTags: (result, error, arg) => [ - { type: Tags.FLIGHT_PLAN, id: arg.flightId }, - ], - }, - }, -}); - -export * from "./_liberationApi"; diff --git a/client/src/api/mapSlice.ts b/client/src/api/mapSlice.ts deleted file mode 100644 index 9cf743535..000000000 --- a/client/src/api/mapSlice.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { createSlice } from "@reduxjs/toolkit"; -import { LatLngLiteral } from "leaflet"; - -interface MapState { - center: LatLngLiteral; -} - -const initialState: MapState = { - center: { lat: 0, lng: 0 }, -}; - -const mapSlice = createSlice({ - name: "map", - initialState: initialState, - reducers: {}, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - if (action.payload.map_center != null) { - state.center = action.payload.map_center; - } - }); - builder.addCase(gameUnloaded, (state) => { - state.center = { lat: 0, lng: 0 }; - }); - }, -}); - -export const selectMapCenter = (state: RootState) => state.map.center; - -export default mapSlice.reducer; diff --git a/client/src/api/navMeshSlice.ts b/client/src/api/navMeshSlice.ts deleted file mode 100644 index 3aa5cf67c..000000000 --- a/client/src/api/navMeshSlice.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { NavMesh, NavMeshPoly } from "./liberationApi"; -import { createSlice, PayloadAction } from "@reduxjs/toolkit"; - -interface NavMeshState { - blue: NavMeshPoly[]; - red: NavMeshPoly[]; -} - -const initialState: NavMeshState = { - blue: [], - red: [], -}; - -export interface INavMeshUpdate { - blue: boolean; - mesh: NavMesh; -} - -const navMeshSlice = createSlice({ - name: "navmesh", - initialState: initialState, - reducers: { - updated: (state, action: PayloadAction) => { - for (const [blue, navmesh] of Object.entries(action.payload)) { - const data = {blue: (blue === "true"), mesh: navmesh} as unknown as INavMeshUpdate - const polys = data.mesh.polys; - if (data.blue) { - state.blue = polys; - } else { - state.red = polys; - } - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.blue = action.payload.navmeshes.blue.polys; - state.red = action.payload.navmeshes.red.polys; - }); - builder.addCase(gameUnloaded, (state) => { - state.blue = []; - state.red = []; - }); - }, -}); - -export const { updated: navMeshUpdated } = navMeshSlice.actions; - -export const selectNavMeshes = (state: RootState) => state.navmeshes; - -export default navMeshSlice.reducer; diff --git a/client/src/api/supplyRoutesSlice.ts b/client/src/api/supplyRoutesSlice.ts deleted file mode 100644 index d5683b89a..000000000 --- a/client/src/api/supplyRoutesSlice.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { SupplyRoute } from "./liberationApi"; -import { createSlice } from "@reduxjs/toolkit"; - -interface SupplyRoutesState { - routes: SupplyRoute[]; -} - -const initialState: SupplyRoutesState = { - routes: [], -}; - -export const supplyRoutesSlice = createSlice({ - name: "supplyRoutes", - initialState, - reducers: {}, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.routes = action.payload.supply_routes; - }); - builder.addCase(gameUnloaded, (state) => { - state.routes = []; - }); - }, -}); - -export const selectSupplyRoutes = (state: RootState) => state.supplyRoutes; - -export default supplyRoutesSlice.reducer; diff --git a/client/src/api/tgosSlice.ts b/client/src/api/tgosSlice.ts deleted file mode 100644 index e47163928..000000000 --- a/client/src/api/tgosSlice.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { Tgo } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface TgosState { - tgos: { [key: string]: Tgo }; -} - -const initialState: TgosState = { - tgos: {}, -}; - -export const tgosSlice = createSlice({ - name: "tgos", - initialState, - reducers: { - updateTgo: (state, action: PayloadAction) => { - for (const tgo of action.payload) { - state.tgos[tgo.id] = tgo; - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.tgos = action.payload.tgos.reduce( - (acc: { [key: string]: Tgo }, curr) => { - acc[curr.id] = curr; - return acc; - }, - {} - ); - }); - builder.addCase(gameUnloaded, (state) => { - state.tgos = {}; - }); - }, -}); - -export const { updateTgo } = tgosSlice.actions; - -export const selectTgos = (state: RootState) => state.tgos; - -export default tgosSlice.reducer; diff --git a/client/src/api/threatZonesSlice.ts b/client/src/api/threatZonesSlice.ts deleted file mode 100644 index c0d35d4c4..000000000 --- a/client/src/api/threatZonesSlice.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { ThreatZoneContainer, ThreatZones } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface ThreatZonesState { - zones: ThreatZoneContainer; -} - -const initialState: ThreatZonesState = { - zones: { - blue: { - full: [], - aircraft: [], - air_defenses: [], - radar_sams: [], - }, - red: { - full: [], - aircraft: [], - air_defenses: [], - radar_sams: [], - }, - }, -}; - -export interface IThreatZoneUpdate { - blue: boolean; - zones: ThreatZones; -} - -export const threatZonesSlice = createSlice({ - name: "threatZonesState", - initialState, - reducers: { - updated: (state, action: PayloadAction) => { - for (const [blue, zones] of Object.entries(action.payload)) { - const data = {blue: (blue === "true"), zones: zones} as unknown as IThreatZoneUpdate - if (data.blue) { - state.zones.blue = data.zones; - } else { - state.zones.red = data.zones; - } - } - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.zones = action.payload.threat_zones; - }); - builder.addCase(gameUnloaded, (state) => { - state.zones = initialState.zones; - }); - }, -}); - -export const { updated: threatZonesUpdated } = threatZonesSlice.actions; - -export const selectThreatZones = (state: RootState) => state.threatZones; - -export default threatZonesSlice.reducer; diff --git a/client/src/api/unculledZonesSlice.ts b/client/src/api/unculledZonesSlice.ts deleted file mode 100644 index 6ffd37c9f..000000000 --- a/client/src/api/unculledZonesSlice.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { RootState } from "../app/store"; -import { gameLoaded, gameUnloaded } from "./actions"; -import { UnculledZone } from "./liberationApi"; -import { PayloadAction, createSlice } from "@reduxjs/toolkit"; - -interface UnculledZonesState { - zones: UnculledZone[]; -} - -const initialState: UnculledZonesState = { - zones: [], -}; - -export const unculledZonesSlice = createSlice({ - name: "unculledZonesState", - initialState, - reducers: { - updated: (state, action: PayloadAction) => { - state.zones = action.payload; - }, - }, - extraReducers: (builder) => { - builder.addCase(gameLoaded, (state, action) => { - state.zones = action.payload.unculled_zones; - }); - builder.addCase(gameUnloaded, (state) => { - state.zones = initialState.zones; - }); - }, -}); - -export const { updated: unculledZonesUpdated } = unculledZonesSlice.actions; - -export const selectUnculledZones = (state: RootState) => state.unculledZones; - -export default unculledZonesSlice.reducer; diff --git a/client/src/app/hooks.ts b/client/src/app/hooks.ts deleted file mode 100644 index 3a3cf12f4..000000000 --- a/client/src/app/hooks.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { RootState, AppDispatch } from "./store"; -import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"; - -// Use throughout your app instead of plain `useDispatch` and `useSelector` -export const useAppDispatch = () => useDispatch(); -export const useAppSelector: TypedUseSelectorHook = useSelector; diff --git a/client/src/app/store.ts b/client/src/app/store.ts deleted file mode 100644 index bbb6eb83d..000000000 --- a/client/src/app/store.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { baseApi } from "../api/baseApi"; -import combatReducer from "../api/combatSlice"; -import controlPointsReducer from "../api/controlPointsSlice"; -import flightsReducer from "../api/flightsSlice"; -import frontLinesReducer from "../api/frontLinesSlice"; -import iadsNetworkReducer from "../api/iadsNetworkSlice"; -import mapReducer from "../api/mapSlice"; -import navMeshReducer from "../api/navMeshSlice"; -import supplyRoutesReducer from "../api/supplyRoutesSlice"; -import tgosReducer from "../api/tgosSlice"; -import threatZonesReducer from "../api/threatZonesSlice"; -import unculledZonesReducer from "../api/unculledZonesSlice"; -import { - Action, - PreloadedState, - ThunkAction, - combineReducers, - configureStore, -} from "@reduxjs/toolkit"; - -const rootReducer = combineReducers({ - combat: combatReducer, - controlPoints: controlPointsReducer, - flights: flightsReducer, - frontLines: frontLinesReducer, - map: mapReducer, - navmeshes: navMeshReducer, - supplyRoutes: supplyRoutesReducer, - iadsNetwork: iadsNetworkReducer, - tgos: tgosReducer, - threatZones: threatZonesReducer, - [baseApi.reducerPath]: baseApi.reducer, - unculledZones: unculledZonesReducer, -}); - -export function setupStore(preloadedState?: PreloadedState) { - return configureStore({ - reducer: rootReducer, - middleware: (getDefaultMiddleware) => - getDefaultMiddleware().concat(baseApi.middleware), - preloadedState: preloadedState, - }); -} - -export type AppStore = ReturnType; -export type AppDispatch = AppStore["dispatch"]; -export type RootState = ReturnType; -export type AppThunk = ThunkAction< - ReturnType, - RootState, - unknown, - Action ->; diff --git a/client/src/components/aircraft/Aircraft.test.tsx b/client/src/components/aircraft/Aircraft.test.tsx deleted file mode 100644 index 959efb1fe..000000000 --- a/client/src/components/aircraft/Aircraft.test.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import Aircraft from "./Aircraft"; -import { render } from "@testing-library/react"; -import { Icon } from "leaflet"; - -const mockMarker = jest.fn(); -jest.mock("react-leaflet", () => ({ - Marker: (props: any) => { - mockMarker(props); - }, -})); - -test("grounded aircraft do not render", async () => { - const { container } = render( - - ); - - expect(container).toBeEmptyDOMElement(); -}); - -test("in-flight aircraft render", async () => { - render( - - ); - - expect(mockMarker).toHaveBeenCalledWith( - expect.objectContaining({ - position: { - lat: 10, - lng: 20, - }, - icon: expect.any(Icon), - }) - ); -}); diff --git a/client/src/components/aircraft/Aircraft.tsx b/client/src/components/aircraft/Aircraft.tsx deleted file mode 100644 index c9bdb1848..000000000 --- a/client/src/components/aircraft/Aircraft.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { Flight } from "../../api/liberationApi"; -import { Icon, Point } from "leaflet"; -import { Symbol } from "milsymbol"; -import { Marker } from "react-leaflet"; - -function iconForFlight(flight: Flight) { - const symbol = new Symbol(flight.sidc, { - size: 20, - }); - - return new Icon({ - iconUrl: symbol.toDataURL(), - iconAnchor: new Point(symbol.getAnchor().x, symbol.getAnchor().y), - }); -} - -interface AircraftProps { - flight: Flight; -} - -export default function Aircraft(props: AircraftProps) { - if (!props.flight.position) { - return <>; - } - - return ( - - ); -} diff --git a/client/src/components/aircraft/index.ts b/client/src/components/aircraft/index.ts deleted file mode 100644 index e8019887e..000000000 --- a/client/src/components/aircraft/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Aircraft"; diff --git a/client/src/components/aircraftlayer/AircraftLayer.test.tsx b/client/src/components/aircraftlayer/AircraftLayer.test.tsx deleted file mode 100644 index 3017c5ccc..000000000 --- a/client/src/components/aircraftlayer/AircraftLayer.test.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import AircraftLayer from "./AircraftLayer"; -import { PropsWithChildren } from "react"; - -const mockLayerGroup = jest.fn(); -const mockMarker = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Marker: (props: any) => { - mockMarker(props); - }, -})); - -test("layer is empty by default", async () => { - renderWithProviders(); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockMarker).not.toHaveBeenCalled(); -}); - -test("layer has aircraft if non-empty", async () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - position: { - lat: 0, - lng: 0, - }, - }, - bar: { - id: "bar", - blue: false, - sidc: "", - position: { - lat: 0, - lng: 0, - }, - }, - }, - selected: null, - }, - }, - }); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockMarker).toHaveBeenCalledTimes(2); -}); diff --git a/client/src/components/aircraftlayer/AircraftLayer.tsx b/client/src/components/aircraftlayer/AircraftLayer.tsx deleted file mode 100644 index c7a5fcb2c..000000000 --- a/client/src/components/aircraftlayer/AircraftLayer.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { selectFlights } from "../../api/flightsSlice"; -import { useAppSelector } from "../../app/hooks"; -import Aircraft from "../aircraft"; -import { LayerGroup } from "react-leaflet"; - -export default function AircraftLayer() { - const flights = useAppSelector(selectFlights).flights; - return ( - - {Object.values(flights).map((flight) => { - return ; - })} - - ); -} diff --git a/client/src/components/aircraftlayer/index.ts b/client/src/components/aircraftlayer/index.ts deleted file mode 100644 index f250662ae..000000000 --- a/client/src/components/aircraftlayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./AircraftLayer"; diff --git a/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.test.tsx b/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.test.tsx deleted file mode 100644 index ac4071e12..000000000 --- a/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.test.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import AirDefenseRangeLayer, { colorFor } from "./AirDefenseRangeLayer"; -import { PropsWithChildren } from "react"; - -const mockLayerGroup = jest.fn(); -const mockCircle = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Circle: (props: any) => { - mockCircle(props); - }, -})); - -describe("colorFor", () => { - it("has a unique color for each configuration", () => { - const params = [ - [false, false], - [false, true], - [true, false], - [true, true], - ]; - var colors = new Set(); - for (const [blue, detection] of params) { - colors.add(colorFor(blue, detection)); - } - expect(colors.size).toEqual(4); - }); -}); - -describe("AirDefenseRangeLayer", () => { - it("draws nothing when there are no TGOs", () => { - renderWithProviders(); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockCircle).not.toHaveBeenCalled(); - }); - - it("does not draw wrong range types", () => { - renderWithProviders(, { - preloadedState: { - tgos: { - tgos: { - foo: { - id: "foo", - name: "Foo", - control_point_name: "Bar", - category: "AA", - blue: false, - position: { - lat: 0, - lng: 0, - }, - units: [], - threat_ranges: [], - detection_ranges: [20], - dead: false, - sidc: "", - }, - }, - }, - }, - }); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockCircle).not.toHaveBeenCalled(); - }); - - it("draws threat ranges", () => { - renderWithProviders(, { - preloadedState: { - tgos: { - tgos: { - foo: { - id: "foo", - name: "Foo", - control_point_name: "Bar", - category: "AA", - blue: true, - position: { - lat: 10, - lng: 20, - }, - units: [], - threat_ranges: [10], - detection_ranges: [20], - dead: false, - sidc: "", - }, - }, - }, - }, - }); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockCircle).toHaveBeenCalledWith( - expect.objectContaining({ - center: { - lat: 10, - lng: 20, - }, - radius: 10, - color: colorFor(true, false), - interactive: false, - }) - ); - }); - - it("draws detection ranges", () => { - renderWithProviders(, { - preloadedState: { - tgos: { - tgos: { - foo: { - id: "foo", - name: "Foo", - control_point_name: "Bar", - category: "AA", - blue: true, - position: { - lat: 10, - lng: 20, - }, - units: [], - threat_ranges: [10], - detection_ranges: [20], - dead: false, - sidc: "", - }, - }, - }, - }, - }); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockCircle).toHaveBeenCalledWith( - expect.objectContaining({ - center: { - lat: 10, - lng: 20, - }, - radius: 20, - color: colorFor(true, true), - interactive: false, - }) - ); - }); -}); diff --git a/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx b/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx deleted file mode 100644 index 96c0e7761..000000000 --- a/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Tgo } from "../../api/liberationApi"; -import { selectTgos } from "../../api/tgosSlice"; -import { useAppSelector } from "../../app/hooks"; -import { Circle, LayerGroup } from "react-leaflet"; - -interface TgoRangeCirclesProps { - tgo: Tgo; - blue: boolean; - detection?: boolean; -} - -export function colorFor(blue: boolean, detection: boolean) { - if (blue) { - return detection ? "#bb89ff" : "#0084ff"; - } - return detection ? "#eee17b" : "#c85050"; -} - -const TgoRangeCircles = (props: TgoRangeCirclesProps) => { - const radii = props.detection - ? props.tgo.detection_ranges - : props.tgo.threat_ranges; - const color = colorFor(props.blue, props.detection === true); - const weight = props.detection ? 1 : 2; - - return ( - <> - {radii.map((radius, idx) => { - return ( - - ); - })} - - ); -}; - -interface AirDefenseRangeLayerProps { - blue: boolean; - detection?: boolean; -} - -export const AirDefenseRangeLayer = (props: AirDefenseRangeLayerProps) => { - const tgos = Object.values(useAppSelector(selectTgos).tgos); - var tgosForSide = tgos.filter((tgo) => tgo.blue === props.blue); - - return ( - - {tgosForSide.map((tgo) => { - return ( - - ); - })} - - ); -}; - -export default AirDefenseRangeLayer; diff --git a/client/src/components/airdefenserangelayer/index.ts b/client/src/components/airdefenserangelayer/index.ts deleted file mode 100644 index 906609aad..000000000 --- a/client/src/components/airdefenserangelayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./AirDefenseRangeLayer"; diff --git a/client/src/components/combat/Combat.test.tsx b/client/src/components/combat/Combat.test.tsx deleted file mode 100644 index 888e74266..000000000 --- a/client/src/components/combat/Combat.test.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import Combat from "./Combat"; -import { LatLng } from "leaflet"; - -const mockPolyline = jest.fn(); -const mockPolygon = jest.fn(); -jest.mock("react-leaflet", () => ({ - Polyline: (props: any) => { - mockPolyline(props); - }, - Polygon: (props: any) => { - mockPolygon(props); - }, -})); - -describe("Combat", () => { - describe("footprint", () => { - it("is not interactive", () => { - renderWithProviders( - - ); - expect(mockPolygon).toBeCalledWith( - expect.objectContaining({ interactive: false }) - ); - }); - - // Fails because we don't handle multi-poly combat footprints correctly. - it.skip("renders single polygons", () => { - const boundary = [new LatLng(0, 0), new LatLng(0, 1), new LatLng(1, 0)]; - renderWithProviders( - - ); - expect(mockPolygon).toBeCalledWith( - expect.objectContaining({ positions: boundary }) - ); - }); - - // Fails because we don't handle multi-poly combat footprints correctly. - it.skip("renders multiple polygons", () => { - const boundary = [new LatLng(0, 0), new LatLng(0, 1), new LatLng(1, 0)]; - renderWithProviders( - - ); - expect(mockPolygon).toBeCalledTimes(2); - }); - }); - - describe("lines", () => { - it("is not interactive", () => { - renderWithProviders( - - ); - expect(mockPolyline).toBeCalledWith( - expect.objectContaining({ interactive: false }) - ); - }); - - it("renders single line", () => { - renderWithProviders( - - ); - expect(mockPolyline).toBeCalledWith( - expect.objectContaining({ - positions: [new LatLng(0, 0), new LatLng(0, 1)], - }) - ); - }); - - it("renders multiple lines", () => { - renderWithProviders( - - ); - expect(mockPolyline).toBeCalledTimes(2); - }); - }); - - it("renders nothing if no footprint or targets", () => { - const { container } = renderWithProviders( - - ); - expect(container).toBeEmptyDOMElement(); - }); -}); diff --git a/client/src/components/combat/Combat.tsx b/client/src/components/combat/Combat.tsx deleted file mode 100644 index 8f9f0ea2b..000000000 --- a/client/src/components/combat/Combat.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import CombatModel from "../../api/combat"; -import { LatLng } from "leaflet"; -import { Polygon, Polyline } from "react-leaflet"; - -interface CombatProps { - combat: CombatModel; -} - -function CombatFootprint(props: CombatProps) { - if (!props.combat.footprint) { - return <>; - } - - return ( - - ); -} - -function CombatLines(props: CombatProps) { - if (!props.combat.flight_position || !props.combat.target_positions) { - return <>; - } - - const flightPosition: LatLng = props.combat.flight_position; - return ( - <> - {props.combat.target_positions.map((position, idx) => { - return ( - - ); - })} - - ); -} - -export default function Combat(props: CombatProps) { - return ( - <> - - - - ); -} diff --git a/client/src/components/combat/index.ts b/client/src/components/combat/index.ts deleted file mode 100644 index c7d266dad..000000000 --- a/client/src/components/combat/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Combat"; diff --git a/client/src/components/combatlayer/CombatLayer.test.tsx b/client/src/components/combatlayer/CombatLayer.test.tsx deleted file mode 100644 index 46aa8d252..000000000 --- a/client/src/components/combatlayer/CombatLayer.test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import CombatLayer from "./CombatLayer"; -import { LatLng } from "leaflet"; -import { PropsWithChildren } from "react"; - -const mockPolyline = jest.fn(); -const mockLayerGroup = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Polyline: (props: any) => { - mockPolyline(props); - }, -})); - -describe("CombatLayer", () => { - it("renders each combat", () => { - renderWithProviders(, { - preloadedState: { - combat: { - combat: { - foo: { - id: "foo", - flight_position: new LatLng(0, 0), - target_positions: [new LatLng(0, 1)], - footprint: null, - }, - bar: { - id: "foo", - flight_position: new LatLng(0, 0), - target_positions: [new LatLng(0, 1)], - footprint: null, - }, - }, - }, - }, - }); - expect(mockPolyline).toBeCalledTimes(2); - }); - - it("renders LayerGroup but no contents if no combat", () => { - renderWithProviders(); - expect(mockLayerGroup).toBeCalledTimes(1); - expect(mockPolyline).not.toHaveBeenCalled(); - }); -}); diff --git a/client/src/components/combatlayer/CombatLayer.tsx b/client/src/components/combatlayer/CombatLayer.tsx deleted file mode 100644 index 0a5de15da..000000000 --- a/client/src/components/combatlayer/CombatLayer.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { selectCombat } from "../../api/combatSlice"; -import { useAppSelector } from "../../app/hooks"; -import Combat from "../combat/Combat"; -import { LayerGroup } from "react-leaflet"; - -export default function CombatLayer() { - const combats = useAppSelector(selectCombat); - return ( - - {Object.values(combats.combat).map((combat) => { - return ; - })} - ( - - ); -} diff --git a/client/src/components/combatlayer/index.ts b/client/src/components/combatlayer/index.ts deleted file mode 100644 index 98aaaa74b..000000000 --- a/client/src/components/combatlayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CombatLayer"; diff --git a/client/src/components/controlpoints/ControlPoint.tsx b/client/src/components/controlpoints/ControlPoint.tsx deleted file mode 100644 index 316fe5d3a..000000000 --- a/client/src/components/controlpoints/ControlPoint.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ControlPoint as ControlPointModel } from "../../api/liberationApi"; -import { MobileControlPoint } from "./MobileControlPoint"; -import { StaticControlPoint } from "./StaticControlPoint"; - -interface ControlPointProps { - controlPoint: ControlPointModel; -} - -export default function ControlPoint(props: ControlPointProps) { - if (props.controlPoint.mobile) { - return ; - } else { - return ; - } -} diff --git a/client/src/components/controlpoints/EventHandlers.ts b/client/src/components/controlpoints/EventHandlers.ts deleted file mode 100644 index 3a347b9db..000000000 --- a/client/src/components/controlpoints/EventHandlers.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ControlPoint } from "../../api/_liberationApi"; -import backend from "../../api/backend"; - -function openInfoDialog(controlPoint: ControlPoint) { - backend.post(`/qt/info/control-point/${controlPoint.id}`); -} - -function openNewPackageDialog(controlPoint: ControlPoint) { - backend.post(`/qt/create-package/control-point/${controlPoint.id}`); -} - -export const makeLocationMarkerEventHandlers = (controlPoint: ControlPoint) => { - return { - click: () => { - openInfoDialog(controlPoint); - }, - - contextmenu: () => { - openNewPackageDialog(controlPoint); - }, - }; -}; diff --git a/client/src/components/controlpoints/Icons.tsx b/client/src/components/controlpoints/Icons.tsx deleted file mode 100644 index 48e090413..000000000 --- a/client/src/components/controlpoints/Icons.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { ControlPoint } from "../../api/_liberationApi"; -import { Icon, Point } from "leaflet"; -import { Symbol } from "milsymbol"; - -export const iconForControlPoint = (cp: ControlPoint) => { - const symbol = new Symbol(cp.sidc, { - size: 24, - colorMode: "Dark", - }); - - return new Icon({ - iconUrl: symbol.toDataURL(), - iconAnchor: new Point(symbol.getAnchor().x, symbol.getAnchor().y), - }); -}; diff --git a/client/src/components/controlpoints/LocationTooltipText.tsx b/client/src/components/controlpoints/LocationTooltipText.tsx deleted file mode 100644 index 1c8cc3016..000000000 --- a/client/src/components/controlpoints/LocationTooltipText.tsx +++ /dev/null @@ -1,9 +0,0 @@ -interface LocationTooltipTextProps { - name: string; -} - -export const LocationTooltipText = (props: LocationTooltipTextProps) => { - return

{props.name}

; -}; - -export default LocationTooltipText; diff --git a/client/src/components/controlpoints/MobileControlPoint.tsx b/client/src/components/controlpoints/MobileControlPoint.tsx deleted file mode 100644 index dcbaaade4..000000000 --- a/client/src/components/controlpoints/MobileControlPoint.tsx +++ /dev/null @@ -1,228 +0,0 @@ -import { ControlPoint } from "../../api/_liberationApi"; -import backend from "../../api/backend"; -import { - useClearControlPointDestinationMutation, - useSetControlPointDestinationMutation, -} from "../../api/liberationApi"; -import { makeLocationMarkerEventHandlers } from "./EventHandlers"; -import { iconForControlPoint } from "./Icons"; -import LocationTooltipText from "./LocationTooltipText"; -import { MovementPath, MovementPathHandle } from "./MovementPath"; -import { StaticControlPoint } from "./StaticControlPoint"; -import { LatLng, Marker as LMarker, LatLngLiteral } from "leaflet"; -import { useCallback, useEffect, useRef, useState } from "react"; -import ReactDOMServer from "react-dom/server"; -import { Marker, Tooltip } from "react-leaflet"; - -function metersToNauticalMiles(meters: number) { - return meters * 0.000539957; -} - -function formatLatLng(latLng: LatLng) { - const lat = latLng.lat.toFixed(2); - const lng = latLng.lng.toFixed(2); - const ns = latLng.lat >= 0 ? "N" : "S"; - const ew = latLng.lng >= 0 ? "E" : "W"; - return `${lat}°${ns} ${lng}°${ew}`; -} - -function destinationTooltipText( - cp: ControlPoint, - destinationish: LatLngLiteral, - inRange: boolean -) { - const destination = new LatLng(destinationish.lat, destinationish.lng); - const distance = metersToNauticalMiles( - destination.distanceTo(cp.position) - ).toFixed(1); - if (!inRange) { - return `Out of range (${distance}nm away)`; - } - const dest = formatLatLng(destination); - return `${cp.name} moving ${distance}nm to ${dest} next turn`; -} - -interface PrimaryMarkerProps { - controlPoint: ControlPoint; -} - -/** - * The primary control point marker. For non-mobile control points, this has - * fairly simple behavior: it's a marker in a fixed location that can manage - * units and can have missions planned against it. - * - * For mobile control points, this is a draggable marker. If the control point - * has a destination (either because it was dragged after render, or because it - * had a destination in the game that was loaded), the unit management and - * mission planning behaviors are delegated to SecondaryMarker, and the primary - * marker becomes only a destination marker. It can be dragged to change the - * destination, and can be right clicked to cancel movement. - */ -function PrimaryMarker(props: PrimaryMarkerProps) { - // We can't use normal state to update the marker tooltip or the line points - // because if we set any state in the drag event it will re-render this - // component and all children, interrupting dragging. Instead, keep refs to - // the objects and mutate them directly. - // - // For the same reason, the path is owned by this component, because updating - // sibling state would be messy. Lifting the state into the parent would still - // cause this component to redraw. - const markerRef = useRef(null); - const pathRef = useRef(null); - - const [hasDestination, setHasDestination] = useState( - props.controlPoint.destination != null - ); - const [position, setPosition] = useState( - props.controlPoint.destination - ? props.controlPoint.destination - : props.controlPoint.position - ); - - const setDestination = useCallback((destination: LatLng) => { - setPosition(destination); - setHasDestination(true); - }, []); - - const resetDestination = useCallback(() => { - setPosition(props.controlPoint.position); - setHasDestination(false); - }, [props]); - - const [putDestination, { isLoading }] = - useSetControlPointDestinationMutation(); - const [cancelTravel] = useClearControlPointDestinationMutation(); - - useEffect(() => { - markerRef.current?.setTooltipContent( - props.controlPoint.destination - ? destinationTooltipText( - props.controlPoint, - props.controlPoint.destination, - true - ) - : ReactDOMServer.renderToString( - - ) - ); - }); - - const locationClickHandlers = makeLocationMarkerEventHandlers( - props.controlPoint - ); - - return ( - <> - { - if (ref != null) { - markerRef.current = ref; - } - }} - eventHandlers={{ - click: () => { - if (!hasDestination) { - locationClickHandlers.click(); - } - }, - contextmenu: () => { - if (props.controlPoint.destination) { - cancelTravel({ cpId: props.controlPoint.id }).then(() => { - resetDestination(); - }); - } else { - locationClickHandlers.contextmenu(); - } - }, - drag: (event) => { - const destination = event.target.getLatLng(); - backend - .get( - `/control-points/${props.controlPoint.id}/destination-in-range?lat=${destination.lat}&lng=${destination.lng}` - ) - .then((inRange) => { - markerRef.current?.setTooltipContent( - destinationTooltipText( - props.controlPoint, - destination, - inRange.data - ) - ); - }); - pathRef.current?.setDestination(destination); - }, - dragend: async (event) => { - const currentPosition = new LatLng(position.lat, position.lng); - const destination = event.target.getLatLng(); - setDestination(destination); - try { - await putDestination({ - cpId: props.controlPoint.id, - body: { lat: destination.lat, lng: destination.lng }, - }).unwrap(); - } catch (error) { - console.error("setDestination failed", error); - setDestination(currentPosition); - } - }, - }} - > - - - - - ); -} - -interface SecondaryMarkerProps { - controlPoint: ControlPoint; - destination: LatLngLiteral | undefined; -} - -/** - * The secondary marker for a control point. The secondary marker will only be - * shown when the control point has a destination set. For mobile control - * points, the primary marker is draggable, and the secondary marker will be - * shown at the current location iff the control point has been dragged. The - * secondary marker is also the marker that has the normal control point - * interaction options (mission planning and unit management). - */ -function SecondaryMarker(props: SecondaryMarkerProps) { - if (!props.destination) { - return <>; - } - - return ; -} - -interface MobileControlPointProps { - controlPoint: ControlPoint; -} - -export const MobileControlPoint = (props: MobileControlPointProps) => { - return ( - <> - - - - ); -}; diff --git a/client/src/components/controlpoints/MovementPath.tsx b/client/src/components/controlpoints/MovementPath.tsx deleted file mode 100644 index 2b2b5ae0c..000000000 --- a/client/src/components/controlpoints/MovementPath.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { LatLngLiteral, Polyline as LPolyline } from "leaflet"; -import { forwardRef, useImperativeHandle, useRef } from "react"; -import { Polyline } from "react-leaflet"; - -interface MovementPathProps { - source: LatLngLiteral; - destination: LatLngLiteral; -} - -export interface MovementPathHandle { - setDestination: (destination: LatLngLiteral) => void; -} - -export const MovementPath = forwardRef( - (props: MovementPathProps, ref) => { - const lineRef = useRef(null); - useImperativeHandle( - ref, - () => ({ - setDestination: (destination: LatLngLiteral) => { - lineRef.current?.setLatLngs([props.source, destination]); - }, - }), - [props] - ); - return ( - - ); - } -); diff --git a/client/src/components/controlpoints/StaticControlPoint.tsx b/client/src/components/controlpoints/StaticControlPoint.tsx deleted file mode 100644 index bdb0c930e..000000000 --- a/client/src/components/controlpoints/StaticControlPoint.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { ControlPoint } from "../../api/_liberationApi"; -import { makeLocationMarkerEventHandlers } from "./EventHandlers"; -import { iconForControlPoint } from "./Icons"; -import LocationTooltipText from "./LocationTooltipText"; -import { Marker, Tooltip } from "react-leaflet"; - -interface StaticControlPointProps { - controlPoint: ControlPoint; -} - -export const StaticControlPoint = (props: StaticControlPointProps) => { - return ( - - - - - - ); -}; diff --git a/client/src/components/controlpoints/index.ts b/client/src/components/controlpoints/index.ts deleted file mode 100644 index a07b747ea..000000000 --- a/client/src/components/controlpoints/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ControlPoint"; diff --git a/client/src/components/controlpointslayer/ControlPointsLayer.test.tsx b/client/src/components/controlpointslayer/ControlPointsLayer.test.tsx deleted file mode 100644 index 61cbe92b5..000000000 --- a/client/src/components/controlpointslayer/ControlPointsLayer.test.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import ControlPointsLayer from "./ControlPointsLayer"; -import { LatLng } from "leaflet"; -import { PropsWithChildren } from "react"; - -const mockMarker = jest.fn(); -const mockLayerGroup = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Marker: (props: any) => { - mockMarker(props); - }, -})); - -describe("ControlPointsLayer", () => { - it("renders each control point", () => { - renderWithProviders(, { - preloadedState: { - controlPoints: { - controlPoints: { - foo: { - id: "foo", - name: "Foo", - blue: true, - position: new LatLng(0, 0), - mobile: false, - sidc: "", - }, - bar: { - id: "bar", - name: "Bar", - blue: false, - position: new LatLng(1, 0), - mobile: false, - sidc: "", - }, - }, - }, - }, - }); - expect(mockMarker).toBeCalledTimes(2); - }); - - it("renders LayerGroup but no contents if no combat", () => { - renderWithProviders(); - expect(mockLayerGroup).toBeCalledTimes(1); - expect(mockMarker).not.toHaveBeenCalled(); - }); -}); diff --git a/client/src/components/controlpointslayer/ControlPointsLayer.tsx b/client/src/components/controlpointslayer/ControlPointsLayer.tsx deleted file mode 100644 index a4e0de15a..000000000 --- a/client/src/components/controlpointslayer/ControlPointsLayer.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { selectControlPoints } from "../../api/controlPointsSlice"; -import { useAppSelector } from "../../app/hooks"; -import ControlPoint from "../controlpoints"; -import { LayerGroup } from "react-leaflet"; - -export default function ControlPointsLayer() { - const controlPoints = useAppSelector(selectControlPoints); - return ( - - {Object.values(controlPoints.controlPoints).map((controlPoint) => { - return ( - - ); - })} - - ); -} diff --git a/client/src/components/controlpointslayer/index.ts b/client/src/components/controlpointslayer/index.ts deleted file mode 100644 index dfc5a263d..000000000 --- a/client/src/components/controlpointslayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./ControlPointsLayer"; diff --git a/client/src/components/cullingexclusionzones/CullingExclusionZones.test.tsx b/client/src/components/cullingexclusionzones/CullingExclusionZones.test.tsx deleted file mode 100644 index 3e78ae1ce..000000000 --- a/client/src/components/cullingexclusionzones/CullingExclusionZones.test.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import CullingExclusionZones from "./CullingExclusionZones"; -import { PropsWithChildren } from "react"; - -const mockCircle = jest.fn(); -const mockLayerGroup = jest.fn(); -const mockLayerControlOverlay = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - LayersControl: { - Overlay: (props: PropsWithChildren) => { - mockLayerControlOverlay(props); - return <>{props.children}; - }, - }, - Circle: (props: any) => { - mockCircle(props); - }, -})); - -describe("CullingExclusionZones", () => { - it("is empty there are no exclusion zones", () => { - renderWithProviders(); - expect(mockCircle).not.toHaveBeenCalled(); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - expect(mockLayerControlOverlay).toHaveBeenCalledTimes(1); - }); - - describe("zone circles", () => { - it("are drawn in the correct locations", () => { - renderWithProviders(, { - preloadedState: { - unculledZones: { - zones: [ - { - position: { - lat: 0, - lng: 0, - }, - radius: 10, - }, - { - position: { - lat: 1, - lng: 1, - }, - radius: 2, - }, - ], - }, - }, - }); - expect(mockCircle).toHaveBeenCalledTimes(2); - expect(mockCircle).toHaveBeenCalledWith( - expect.objectContaining({ - center: { - lat: 0, - lng: 0, - }, - radius: 10, - }) - ); - expect(mockCircle).toHaveBeenCalledWith( - expect.objectContaining({ - center: { - lat: 1, - lng: 1, - }, - radius: 2, - }) - ); - }); - it("are not interactive", () => {}); - }); -}); diff --git a/client/src/components/cullingexclusionzones/CullingExclusionZones.tsx b/client/src/components/cullingexclusionzones/CullingExclusionZones.tsx deleted file mode 100644 index 6fe0cc8b0..000000000 --- a/client/src/components/cullingexclusionzones/CullingExclusionZones.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { UnculledZone } from "../../api/liberationApi"; -import { selectUnculledZones } from "../../api/unculledZonesSlice"; -import { useAppSelector } from "../../app/hooks"; -import { LayerGroup, LayersControl, Circle } from "react-leaflet"; - -interface CullingExclusionCirclesProps { - zones: UnculledZone[]; -} - -const CullingExclusionCircles = (props: CullingExclusionCirclesProps) => { - return ( - <> - - {props.zones.map((zone, idx) => { - return ( - - ); - })} - - - ); -}; - -export default function CullingExclusionZones() { - const data = useAppSelector(selectUnculledZones).zones; - - return ( - - - - ); -} diff --git a/client/src/components/cullingexclusionzones/index.ts b/client/src/components/cullingexclusionzones/index.ts deleted file mode 100644 index 5c74e33e1..000000000 --- a/client/src/components/cullingexclusionzones/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CullingExclusionZones"; diff --git a/client/src/components/flightplan/FlightPlan.tsx b/client/src/components/flightplan/FlightPlan.tsx deleted file mode 100644 index c12f74770..000000000 --- a/client/src/components/flightplan/FlightPlan.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { Flight } from "../../api/liberationApi"; -import { useGetCommitBoundaryForFlightQuery } from "../../api/liberationApi"; -import WaypointMarker from "../waypointmarker"; -import { Polyline as LPolyline } from "leaflet"; -import { ReactElement, useEffect, useRef } from "react"; -import { Polyline } from "react-leaflet"; - -const BLUE_PATH = "#0084ff"; -const RED_PATH = "#c85050"; -const SELECTED_PATH = "#ffff00"; - -interface FlightPlanProps { - flight: Flight; - selected: boolean; - highlight?: boolean; -} - -const pathColor = (props: FlightPlanProps) => { - if (props.selected && props.highlight) { - return SELECTED_PATH; - } else if (props.flight.blue) { - return BLUE_PATH; - } else { - return RED_PATH; - } -}; - -function FlightPlanPath(props: FlightPlanProps) { - const color = pathColor(props); - const waypoints = props.flight.waypoints; - - const polylineRef = useRef(null); - - // Flight paths should be drawn under everything else. There seems to be an - // issue where `interactive: false` doesn't do as its told (there's nuance, - // see the bug for details). It looks better if we draw the other elements on - // top of the flight plans anyway, so just push the flight plan to the back. - // - // https://github.com/dcs-liberation/dcs_liberation/issues/3295 - // - // It's not possible to z-index a polyline (and leaflet says it never will be, - // because this is a limitation of SVG, not leaflet: - // https://github.com/Leaflet/Leaflet/issues/185), so we need to use - // bringToBack() to push the flight paths to the back of the drawing once - // they've been added to the map. They'll still draw on top of the map, but - // behind everything than was added before them. Anything added after always - // goes on top. - useEffect(() => { - if (!props.selected) { - polylineRef.current?.bringToBack(); - } - }); - - if (waypoints == null) { - return <>; - } - const points = waypoints - .filter((waypoint) => waypoint.include_in_path) - .map((waypoint) => waypoint.position); - - return ( - - ); -} - -const WaypointMarkers = (props: FlightPlanProps) => { - if (!props.selected || props.flight.waypoints == null) { - return <>; - } - - var markers: ReactElement[] = []; - props.flight.waypoints?.forEach((p, idx) => { - if (p.should_mark) { - markers.push( - - ); - } - }); - - return <>{markers}; -}; - -interface CommitBoundaryProps { - flightId: string; - selected: boolean; -} - -function CommitBoundary(props: CommitBoundaryProps) { - const { data, error, isLoading } = useGetCommitBoundaryForFlightQuery( - { - flightId: props.flightId, - }, - // RTK Query doesn't seem to allow us to invalidate the cache from anything - // but a mutation, but this data can be invalidated by events from the - // websocket. Just disable the cache for this. - // - // This isn't perfect. It won't redraw until the component remounts. There - // doesn't appear to be a better way. - { refetchOnMountOrArgChange: true } - ); - if (isLoading) { - return <>; - } - if (error) { - console.error(`Error loading commit boundary for ${props.flightId}`, error); - return <>; - } - if (!data) { - console.log( - `Null response data when loading commit boundary for ${props.flightId}` - ); - return <>; - } - return ( - - ); -} - -function CommitBoundaryIfSelected(props: CommitBoundaryProps) { - if (!props.selected) { - return <>; - } - return ; -} - -export default function FlightPlan(props: FlightPlanProps) { - return ( - <> - - - - - ); -} diff --git a/client/src/components/flightplan/index.ts b/client/src/components/flightplan/index.ts deleted file mode 100644 index b741ce96c..000000000 --- a/client/src/components/flightplan/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FlightPlan"; diff --git a/client/src/components/flightplanslayer/FlightPlansLayer.test.tsx b/client/src/components/flightplanslayer/FlightPlansLayer.test.tsx deleted file mode 100644 index 820957d0e..000000000 --- a/client/src/components/flightplanslayer/FlightPlansLayer.test.tsx +++ /dev/null @@ -1,409 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import FlightPlansLayer from "./FlightPlansLayer"; -import { PropsWithChildren } from "react"; - -const mockPolyline = jest.fn(); -const mockLayerGroup = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Polyline: (props: any) => { - mockPolyline(props); - }, -})); - -// The waypoints in test data below should all use `should_make: false`. Markers -// need useMap() to check the zoom level to decide if they should be drawn or -// not, and we don't have good options here for mocking that behavior. -describe("FlightPlansLayer", () => { - describe("unselected flights", () => { - it("are drawn", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - bar: { - id: "bar", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: null, - }, - }, - }); - - // For some reason passing ref to PolyLine causes it and its group to be - // redrawn, so these numbers don't match what you'd expect from the test. - // It probably needs to be rewritten without mocks. - expect(mockPolyline).toHaveBeenCalledTimes(3); - expect(mockLayerGroup).toBeCalledTimes(2); - }); - it("are not drawn if wrong coalition", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - bar: { - id: "bar", - blue: false, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: null, - }, - }, - }); - expect(mockPolyline).toHaveBeenCalledTimes(1); - expect(mockLayerGroup).toBeCalledTimes(1); - }); - it("are not drawn when only selected flights are to be drawn", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: null, - }, - }, - }); - expect(mockPolyline).not.toHaveBeenCalled(); - expect(mockLayerGroup).toBeCalledTimes(1); - }); - }); - describe("selected flights", () => { - it("are drawn", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - bar: { - id: "bar", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: "foo", - }, - }, - }); - expect(mockPolyline).toHaveBeenCalledTimes(2); - expect(mockLayerGroup).toBeCalledTimes(1); - }); - it("are not drawn twice", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: true, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: "foo", - }, - }, - }); - expect(mockPolyline).toHaveBeenCalledTimes(1); - expect(mockLayerGroup).toBeCalledTimes(1); - }); - it("are not drawn if red", () => { - renderWithProviders(, { - preloadedState: { - flights: { - flights: { - foo: { - id: "foo", - blue: false, - sidc: "", - waypoints: [ - { - name: "", - position: { - lat: 0, - lng: 0, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - { - name: "", - position: { - lat: 1, - lng: 1, - }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: true, - should_mark: false, - include_in_path: true, - timing: "", - }, - ], - }, - }, - selected: "foo", - }, - }, - }); - expect(mockPolyline).not.toHaveBeenCalled(); - expect(mockLayerGroup).toBeCalledTimes(1); - }); - }); - it("are not drawn if there are no flights", () => { - renderWithProviders(); - expect(mockPolyline).not.toHaveBeenCalled(); - expect(mockLayerGroup).toBeCalledTimes(1); - }); -}); diff --git a/client/src/components/flightplanslayer/FlightPlansLayer.tsx b/client/src/components/flightplanslayer/FlightPlansLayer.tsx deleted file mode 100644 index 7f8ede202..000000000 --- a/client/src/components/flightplanslayer/FlightPlansLayer.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { selectFlights, selectSelectedFlight } from "../../api/flightsSlice"; -import { Flight } from "../../api/liberationApi"; -import { useAppSelector } from "../../app/hooks"; -import FlightPlan from "../flightplan"; -import { LayerGroup } from "react-leaflet"; - -interface FlightPlansLayerProps { - blue: boolean; - selectedOnly?: true; -} - -function SelectedFlightPlan(props: FlightPlansLayerProps) { - const flight = useAppSelector(selectSelectedFlight); - if (!flight) { - return <>; - } - - if (!props.blue) { - // We don't currently support playing as red, so nothing to draw. - return <>; - } - - return ( - - ); -} - -function UnselectedFlightPlans(props: FlightPlansLayerProps) { - const flightData = useAppSelector(selectFlights); - const isNotSelected = (flight: Flight) => { - if (flightData.selected == null) { - return true; - } - return flightData.selected !== flight.id; - }; - - if (props.selectedOnly) { - return <>; - } - - return ( - <> - {Object.values(flightData.flights) - .filter(isNotSelected) - .filter((flight) => props.blue === flight.blue) - .map((flight) => { - return ( - - ); - })} - - ); -} - -export default function FlightPlansLayer(props: FlightPlansLayerProps) { - return ( - - - - - ); -} diff --git a/client/src/components/flightplanslayer/index.ts b/client/src/components/flightplanslayer/index.ts deleted file mode 100644 index 56248f03c..000000000 --- a/client/src/components/flightplanslayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FlightPlansLayer"; diff --git a/client/src/components/frontline/FrontLine.test.tsx b/client/src/components/frontline/FrontLine.test.tsx deleted file mode 100644 index 62f4132a9..000000000 --- a/client/src/components/frontline/FrontLine.test.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import FrontLine from "./FrontLine"; -import { PolylineProps } from "react-leaflet"; - -const mockPolyline = jest.fn(); -jest.mock("react-leaflet", () => ({ - Polyline: (props: PolylineProps) => { - mockPolyline(props); - }, -})); - -describe("FrontLine", () => { - it("is drawn in the correct location", () => { - const extents = [ - { lat: 0, lng: 0 }, - { lat: 1, lng: 0 }, - ]; - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - positions: extents, - }) - ); - }); -}); diff --git a/client/src/components/frontline/FrontLine.tsx b/client/src/components/frontline/FrontLine.tsx deleted file mode 100644 index 8f402c08d..000000000 --- a/client/src/components/frontline/FrontLine.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { - FrontLine as FrontLineModel, - useOpenNewFrontLinePackageDialogMutation, -} from "../../api/liberationApi"; -import { Polyline } from "react-leaflet"; - -interface FrontLineProps { - front: FrontLineModel; -} - -function FrontLine(props: FrontLineProps) { - const [openNewPackageDialog] = useOpenNewFrontLinePackageDialogMutation(); - return ( - { - openNewPackageDialog({ frontLineId: props.front.id }); - }, - }} - /> - ); -} - -export default FrontLine; diff --git a/client/src/components/frontline/index.ts b/client/src/components/frontline/index.ts deleted file mode 100644 index 5ded594e7..000000000 --- a/client/src/components/frontline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FrontLine"; diff --git a/client/src/components/frontlineslayer/FrontLinesLayer.test.tsx b/client/src/components/frontlineslayer/FrontLinesLayer.test.tsx deleted file mode 100644 index d8a27d4c0..000000000 --- a/client/src/components/frontlineslayer/FrontLinesLayer.test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import FrontLinesLayer from "./FrontLinesLayer"; -import { PropsWithChildren } from "react"; - -const mockPolyline = jest.fn(); -const mockLayerGroup = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Polyline: (props: any) => { - mockPolyline(props); - }, -})); - -// The waypoints in test data below should all use `should_make: false`. Markers -// need useMap() to check the zoom level to decide if they should be drawn or -// not, and we don't have good options here for mocking that behavior. -describe("FrontLinesLayer", () => { - it("draws nothing when there are no front lines", () => { - renderWithProviders(); - expect(mockPolyline).not.toHaveBeenCalled(); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - }); - - it("draws front lines", () => { - const extents = [ - { lat: 0, lng: 0 }, - { lat: 1, lng: 1 }, - ]; - renderWithProviders(, { - preloadedState: { - frontLines: { - fronts: { - foo: { - id: "foo", - extents: extents, - }, - bar: { - id: "bar", - extents: extents, - }, - }, - }, - }, - }); - expect(mockPolyline).toHaveBeenCalledTimes(2); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - positions: extents, - }) - ); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - }); -}); diff --git a/client/src/components/frontlineslayer/FrontLinesLayer.tsx b/client/src/components/frontlineslayer/FrontLinesLayer.tsx deleted file mode 100644 index 70b114052..000000000 --- a/client/src/components/frontlineslayer/FrontLinesLayer.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { selectFrontLines } from "../../api/frontLinesSlice"; -import { useAppSelector } from "../../app/hooks"; -import FrontLine from "../frontline"; -import { LayerGroup } from "react-leaflet"; - -export default function FrontLinesLayer() { - const fronts = useAppSelector(selectFrontLines).fronts; - return ( - - {Object.values(fronts).map((front, idx) => { - return ; - })} - - ); -} diff --git a/client/src/components/frontlineslayer/index.ts b/client/src/components/frontlineslayer/index.ts deleted file mode 100644 index ddde2aa25..000000000 --- a/client/src/components/frontlineslayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./FrontLinesLayer"; diff --git a/client/src/components/iadsnetwork/IadsNetwork.tsx b/client/src/components/iadsnetwork/IadsNetwork.tsx deleted file mode 100644 index 79c236bf4..000000000 --- a/client/src/components/iadsnetwork/IadsNetwork.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { IadsConnection as IadsConnectionModel } from "../../api/liberationApi"; -import { Polyline as LPolyline } from "leaflet"; -import { useRef } from "react"; -import { Polyline, Tooltip } from "react-leaflet"; - -interface IadsConnectionProps { - iads_connection: IadsConnectionModel; -} - -function IadsConnectionTooltip(props: IadsConnectionProps) { - var status = props.iads_connection.active ? "Active" : "Inactive"; - if (props.iads_connection.is_power) { - return Power Connection ({status}); - } else { - return Communication Connection ({status}); - } -} - - -export default function IadsConnection(props: IadsConnectionProps) { - const color = props.iads_connection.is_power ? "#FFD580" : "#87CEEB"; - const path = useRef(); - const weight = 1 - var opacity = props.iads_connection.active ? 1.0 : 0.5 - var dashArray = props.iads_connection.active ? "" : "20" - - return ( - (path.current = ref)} - > - - - ); -} diff --git a/client/src/components/iadsnetwork/index.ts b/client/src/components/iadsnetwork/index.ts deleted file mode 100644 index 90cb64d63..000000000 --- a/client/src/components/iadsnetwork/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./IadsNetwork"; diff --git a/client/src/components/iadsnetworklayer/IadsNetworkLayer.tsx b/client/src/components/iadsnetworklayer/IadsNetworkLayer.tsx deleted file mode 100644 index 869022014..000000000 --- a/client/src/components/iadsnetworklayer/IadsNetworkLayer.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { useAppSelector } from "../../app/hooks"; -import { LayerGroup } from "react-leaflet"; -import IadsConnection from "../iadsnetwork/IadsNetwork"; -import { selectIadsNetwork } from "../../api/iadsNetworkSlice"; - - -interface IadsNetworkLayerProps { - blue: boolean; -} - -export const IadsNetworkLayer = (props: IadsNetworkLayerProps) => { - const connections = Object.values(useAppSelector(selectIadsNetwork).connections); - var iadsConnectionsForSide = connections.filter((connection) => connection.blue === props.blue); - - return ( - - {iadsConnectionsForSide.map((connection) => { - return ( - - ); - })} - - ); -}; - -export default IadsNetworkLayer; diff --git a/client/src/components/iadsnetworklayer/index.ts b/client/src/components/iadsnetworklayer/index.ts deleted file mode 100644 index 7f400dcce..000000000 --- a/client/src/components/iadsnetworklayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./IadsNetworkLayer"; diff --git a/client/src/components/liberationmap/LiberationMap.css b/client/src/components/liberationmap/LiberationMap.css deleted file mode 100644 index 576d5c569..000000000 --- a/client/src/components/liberationmap/LiberationMap.css +++ /dev/null @@ -1,7 +0,0 @@ -@import "~leaflet/dist/leaflet.css"; - -.leaflet-container { - width: 100%; - height: 100%; - min-height: 100vh; -} diff --git a/client/src/components/liberationmap/LiberationMap.tsx b/client/src/components/liberationmap/LiberationMap.tsx deleted file mode 100644 index d631227b6..000000000 --- a/client/src/components/liberationmap/LiberationMap.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { selectMapCenter } from "../../api/mapSlice"; -import { useAppSelector } from "../../app/hooks"; -import AircraftLayer from "../aircraftlayer"; -import AirDefenseRangeLayer from "../airdefenserangelayer"; -import CombatLayer from "../combatlayer"; -import ControlPointsLayer from "../controlpointslayer"; -import CullingExclusionZones from "../cullingexclusionzones/CullingExclusionZones"; -import FlightPlansLayer from "../flightplanslayer"; -import FrontLinesLayer from "../frontlineslayer"; -import Iadsnetworklayer from "../iadsnetworklayer"; -import NavMeshLayer from "../navmesh/NavMeshLayer"; -import LeafletRuler from "../ruler/Ruler"; -import SupplyRoutesLayer from "../supplyrouteslayer"; -import TerrainZonesLayers from "../terrainzones/TerrainZonesLayers"; -import TgosLayer from "../tgoslayer/TgosLayer"; -import { CoalitionThreatZones } from "../threatzones"; -import { WaypointDebugZonesControls } from "../waypointdebugzones/WaypointDebugZonesControls"; -import "./LiberationMap.css"; -import { Map } from "leaflet"; -import { useEffect, useRef } from "react"; -import { BasemapLayer } from "react-esri-leaflet"; -import { LayersControl, MapContainer, ScaleControl } from "react-leaflet"; - -export default function LiberationMap() { - const map = useRef(null); - const mapCenter = useAppSelector(selectMapCenter); - useEffect(() => { - map.current?.setView(mapCenter, 8, { animate: true, duration: 1 }); - }); - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/client/src/components/liberationmap/index.ts b/client/src/components/liberationmap/index.ts deleted file mode 100644 index 82e6d029e..000000000 --- a/client/src/components/liberationmap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./LiberationMap"; diff --git a/client/src/components/navmesh/NavMeshLayer.test.tsx b/client/src/components/navmesh/NavMeshLayer.test.tsx deleted file mode 100644 index a5365e6d6..000000000 --- a/client/src/components/navmesh/NavMeshLayer.test.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import NavMeshLayer from "./NavMeshLayer"; -import { PropsWithChildren } from "react"; - -const mockPolygon = jest.fn(); -const mockLayerGroup = jest.fn(); -jest.mock("react-leaflet", () => ({ - LayerGroup: (props: PropsWithChildren) => { - mockLayerGroup(props); - return <>{props.children}; - }, - Polygon: (props: any) => { - mockPolygon(props); - }, -})); - -// The waypoints in test data below should all use `should_make: false`. Markers -// need useMap() to check the zoom level to decide if they should be drawn or -// not, and we don't have good options here for mocking that behavior. -describe("NavMeshLayer", () => { - it("draws blue meshes", () => { - const poly1 = [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: 1 }, - { lat: 1, lng: 0 }, - ], - ]; - const poly2 = [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: -1 }, - { lat: 1, lng: 0 }, - ], - ]; - renderWithProviders(, { - preloadedState: { - navmeshes: { - blue: [ - { - poly: poly1, - threatened: false, - }, - { - poly: poly2, - threatened: true, - }, - ], - red: [ - { - poly: [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: 2 }, - { lat: 1, lng: 0 }, - ], - ], - threatened: false, - }, - ], - }, - }, - }); - expect(mockPolygon).toHaveBeenCalledTimes(2); - expect(mockPolygon).toHaveBeenCalledWith( - expect.objectContaining({ - fillColor: "#00ff00", - positions: poly1, - interactive: false, - }) - ); - expect(mockPolygon).toHaveBeenCalledWith( - expect.objectContaining({ - fillColor: "#ff0000", - positions: poly2, - interactive: false, - }) - ); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - }); - it("draws red navmesh", () => { - renderWithProviders(, { - preloadedState: { - navmeshes: { - blue: [ - { - poly: [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: 1 }, - { lat: 1, lng: 0 }, - ], - ], - threatened: false, - }, - { - poly: [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: -1 }, - { lat: 1, lng: 0 }, - ], - ], - threatened: true, - }, - ], - red: [ - { - poly: [ - [ - { lat: -1, lng: 0 }, - { lat: 0, lng: 2 }, - { lat: 1, lng: 0 }, - ], - ], - threatened: false, - }, - ], - }, - }, - }); - expect(mockPolygon).toHaveBeenCalledTimes(1); - expect(mockLayerGroup).toHaveBeenCalledTimes(1); - }); -}); diff --git a/client/src/components/navmesh/NavMeshLayer.tsx b/client/src/components/navmesh/NavMeshLayer.tsx deleted file mode 100644 index 6b386a338..000000000 --- a/client/src/components/navmesh/NavMeshLayer.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { selectNavMeshes } from "../../api/navMeshSlice"; -import { useAppSelector } from "../../app/hooks"; -import { LayerGroup, Polygon } from "react-leaflet"; - -interface NavMeshLayerProps { - blue: boolean; -} - -export default function NavMeshLayer(props: NavMeshLayerProps) { - const meshes = useAppSelector(selectNavMeshes); - const mesh = props.blue ? meshes.blue : meshes.red; - return ( - - {mesh.map((zone, idx) => { - return ( - - ); - })} - - ); -} diff --git a/client/src/components/navmesh/index.ts b/client/src/components/navmesh/index.ts deleted file mode 100644 index f867c6806..000000000 --- a/client/src/components/navmesh/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./NavMeshLayer"; diff --git a/client/src/components/ruler/Ruler.css b/client/src/components/ruler/Ruler.css deleted file mode 100644 index 643f774b7..000000000 --- a/client/src/components/ruler/Ruler.css +++ /dev/null @@ -1,9 +0,0 @@ -@import "~leaflet-ruler/src/leaflet-ruler.css"; - -.result-tooltip{ - border-color: #435466; -} - -.moving-tooltip{ - border-color: #435466; -} diff --git a/client/src/components/ruler/Ruler.tsx b/client/src/components/ruler/Ruler.tsx deleted file mode 100644 index 00a789b4d..000000000 --- a/client/src/components/ruler/Ruler.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/// -import { useEffect } from "react"; -import { useMap } from "react-leaflet"; -import L from "leaflet"; -import "leaflet-ruler"; -import "./Ruler.css" - -export default function LeafletRuler() { - const map = useMap(); - - useEffect(() => { - if (!map) return; - - var options = { - position: 'topleft', - circleMarker: { // Leaflet circle marker options for points used in this plugin - color: 'yellow', - radius: 2 - }, - lineStyle: { // Leaflet polyline options for lines used in this plugin - color: 'yellow', - dashArray: '1,6' - }, - lengthUnit: { - factor: 0.539956803, // from km to nm - display: 'NM', - decimal: 2, - label: "Distance", - } - }; - if( L.control.hasOwnProperty('ruler') ) - { - L.control.ruler(options).addTo(map); - } - }, [map]); - - return null; -} diff --git a/client/src/components/ruler/index.ts b/client/src/components/ruler/index.ts deleted file mode 100644 index 10798478f..000000000 --- a/client/src/components/ruler/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {default} from "./Ruler"; diff --git a/client/src/components/ruler/leaflet-ruler.d.ts b/client/src/components/ruler/leaflet-ruler.d.ts deleted file mode 100644 index e72bfae59..000000000 --- a/client/src/components/ruler/leaflet-ruler.d.ts +++ /dev/null @@ -1,37 +0,0 @@ -// Ignoring eslint here because we know L.control.ruler is used in Ruler.tsx - -interface CircleMarker { - color: string; - radius: number; -} - -interface LineStyle { - color: string; - dashArray: string; -} - -interface LengthUnit { - display: string; - decimal: number; - factor: number?; - label: string; -} - -interface AngleUnit { - display: string; - decimal: number; - factor: number?; - label: string; -} - -interface RulerOptions { - position?: string; - circleMarker?: CircleMarker; - lineStyle?: LineStyle; - lengthUnit?: LengthUnit; - angleUnit?: AngleUnit; -} - -declare namespace L.control { - function ruler (options: RulerOptions) : L.Control {} -} diff --git a/client/src/components/socketprovider/socketprovider.tsx b/client/src/components/socketprovider/socketprovider.tsx deleted file mode 100644 index c43db80e2..000000000 --- a/client/src/components/socketprovider/socketprovider.tsx +++ /dev/null @@ -1,36 +0,0 @@ -// Based on https://thenable.io/building-a-use-socket-hook-in-react. -import { WEBSOCKET_URL } from "../../api/backend"; -import { ReactChild, createContext, useEffect, useState } from "react"; - -const socket = new WebSocket(WEBSOCKET_URL); - -export const SocketContext = createContext(socket); - -interface SocketProviderProps { - children: ReactChild; -} - -export const SocketProvider = (props: SocketProviderProps) => { - const [ws, setWs] = useState(socket); - useEffect(() => { - const onClose = () => { - setWs(new WebSocket(WEBSOCKET_URL)); - }; - - const onError = (error: Event) => { - console.log(`Websocket error: ${error}`); - }; - - ws.addEventListener("close", onClose); - ws.addEventListener("error", onError); - - return () => { - ws.removeEventListener("close", onClose); - ws.removeEventListener("error", onError); - }; - }); - - return ( - {props.children} - ); -}; diff --git a/client/src/components/splitlines/SplitLines.test.tsx b/client/src/components/splitlines/SplitLines.test.tsx deleted file mode 100644 index be8e896aa..000000000 --- a/client/src/components/splitlines/SplitLines.test.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import SplitLines from "./SplitLines"; -import { screen } from "@testing-library/dom"; -import { render } from "@testing-library/react"; - -describe("SplitLines", () => { - it("joins items with line break tags", () => { - render( -
- -
- ); - - const container = screen.getByTestId("container"); - expect(container).toContainHTML("foo
bar
baz
"); - }); -}); diff --git a/client/src/components/splitlines/SplitLines.tsx b/client/src/components/splitlines/SplitLines.tsx deleted file mode 100644 index 209771a17..000000000 --- a/client/src/components/splitlines/SplitLines.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Fragment } from "react"; - -interface SplitLinesProps { - items: string[]; -} - -const SplitLines = (props: SplitLinesProps) => { - return ( - <> - {props.items.map((text, idx) => { - return ( - - {text} -
-
- ); - })} - - ); -}; - -export default SplitLines; diff --git a/client/src/components/supplyroute/SupplyRoute.test.tsx b/client/src/components/supplyroute/SupplyRoute.test.tsx deleted file mode 100644 index b4192aca9..000000000 --- a/client/src/components/supplyroute/SupplyRoute.test.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { renderWithProviders } from "../../testutils"; -import SupplyRoute, { RouteColor } from "./SupplyRoute"; -import { screen } from "@testing-library/react"; -import { PropsWithChildren } from "react"; - -const mockPolyline = jest.fn(); -jest.mock("react-leaflet", () => ({ - Polyline: (props: PropsWithChildren) => { - mockPolyline(props); - return <>{props.children}; - }, - Tooltip: (props: PropsWithChildren) => { - return

{props.children}

; - }, -})); - -describe("SupplyRoute", () => { - it("is red when inactive and owned by opfor", () => { - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - color: RouteColor.Red, - }) - ); - }); - - it("is blue when inactive and owned by bluefor", () => { - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - color: RouteColor.Blue, - }) - ); - }); - - it("is orange when contested", () => { - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - color: RouteColor.Contested, - }) - ); - }); - - it("is highlighted when the route has active transports", () => { - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledTimes(2); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - color: RouteColor.Highlight, - }) - ); - }); - - it("is drawn in the right place", () => { - const points = [ - { lat: 0, lng: 0 }, - { lat: 1, lng: 1 }, - ]; - renderWithProviders( - - ); - expect(mockPolyline).toHaveBeenCalledTimes(2); - expect(mockPolyline).toHaveBeenCalledWith( - expect.objectContaining({ - positions: points, - }) - ); - }); - - it("has a tooltip describing an inactive supply route", () => { - renderWithProviders( - - ); - - const tooltip = screen.getByTestId("tooltip"); - expect(tooltip).toHaveTextContent("This supply route is inactive."); - }); - - it("has a tooltip describing active supply routes", () => { - renderWithProviders( - - ); - - const tooltip = screen.getByTestId("tooltip"); - expect(tooltip).toContainHTML("foo
bar"); - }); -}); diff --git a/client/src/components/supplyroute/SupplyRoute.tsx b/client/src/components/supplyroute/SupplyRoute.tsx deleted file mode 100644 index 422700eaf..000000000 --- a/client/src/components/supplyroute/SupplyRoute.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { SupplyRoute as SupplyRouteModel } from "../../api/liberationApi"; -import SplitLines from "../splitlines/SplitLines"; -import { Polyline as LPolyline } from "leaflet"; -import { useEffect, useRef } from "react"; -import { Polyline, Tooltip } from "react-leaflet"; - -export enum RouteColor { - Blue = "#2d3e50", - Contested = "#c85050", - Highlight = "#ffffff", - Red = "#8c1414", -} - -interface SupplyRouteProps { - route: SupplyRouteModel; -} - -function SupplyRouteTooltip(props: SupplyRouteProps) { - if (!props.route.active_transports.length) { - return This supply route is inactive.; - } - - return ( - - - - ); -} - -function ActiveSupplyRouteHighlight(props: SupplyRouteProps) { - if (!props.route.active_transports.length) { - return <>; - } - - return ( - - ); -} - -function colorFor(route: SupplyRouteModel) { - if (route.front_active) { - return RouteColor.Contested; - } - if (route.blue) { - return RouteColor.Blue; - } - return RouteColor.Red; -} - -export default function SupplyRoute(props: SupplyRouteProps) { - const color = colorFor(props.route); - const weight = props.route.is_sea ? 4 : 6; - - const path = useRef(); - - useEffect(() => { - // Ensure that the highlight line draws on top of this. We have to bring - // this to the back rather than bringing the highlight to the front because - // the highlight won't necessarily be drawn yet. - path.current?.bringToBack(); - }); - - return ( - (path.current = ref)} - > - - - - ); -} diff --git a/client/src/components/supplyroute/index.ts b/client/src/components/supplyroute/index.ts deleted file mode 100644 index 4c81c3faf..000000000 --- a/client/src/components/supplyroute/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./SupplyRoute"; diff --git a/client/src/components/supplyrouteslayer/SupplyRoutesLayer.tsx b/client/src/components/supplyrouteslayer/SupplyRoutesLayer.tsx deleted file mode 100644 index 07f642e03..000000000 --- a/client/src/components/supplyrouteslayer/SupplyRoutesLayer.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { selectSupplyRoutes } from "../../api/supplyRoutesSlice"; -import { useAppSelector } from "../../app/hooks"; -import SupplyRoute from "../supplyroute/SupplyRoute"; -import { LayerGroup } from "react-leaflet"; - -export default function SupplyRoutesLayer() { - const routes = useAppSelector(selectSupplyRoutes).routes; - return ( - - {routes.map((route) => { - return ; - })} - - ); -} diff --git a/client/src/components/supplyrouteslayer/index.ts b/client/src/components/supplyrouteslayer/index.ts deleted file mode 100644 index 4fe62c3b7..000000000 --- a/client/src/components/supplyrouteslayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./SupplyRoutesLayer"; diff --git a/client/src/components/terrainzones/TerrainZonesLayers.tsx b/client/src/components/terrainzones/TerrainZonesLayers.tsx deleted file mode 100644 index 5d5bb2c36..000000000 --- a/client/src/components/terrainzones/TerrainZonesLayers.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { useGetTerrainZonesQuery } from "../../api/liberationApi"; -import { LatLngLiteral } from "leaflet"; -import { LayerGroup, LayersControl, Polygon } from "react-leaflet"; - -interface TerrainZoneLayerProps { - zones: LatLngLiteral[][][]; - color: string; - fillColor: string; -} - -function TerrainZoneLayer(props: TerrainZoneLayerProps) { - return ( - - {props.zones.map((poly, idx) => { - return ( - - ); - })} - - ); -} - -export default function TerrainZonesLayers() { - const { data, error, isLoading } = useGetTerrainZonesQuery(); - var exclusion = <>; - var inclusion = <>; - var sea = <>; - - if (error) { - console.error("Error while loading terrain zones", error); - } else if (isLoading) { - } else if (!data) { - console.log("Empty response when loading terrain zones"); - } else { - exclusion = ( - - ); - inclusion = ( - - ); - sea = ( - - ); - } - return ( - <> - - {inclusion} - - - {exclusion} - - {sea} - - ); -} diff --git a/client/src/components/terrainzones/index.ts b/client/src/components/terrainzones/index.ts deleted file mode 100644 index 87d28bd1f..000000000 --- a/client/src/components/terrainzones/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TerrainZonesLayers"; diff --git a/client/src/components/tgos/Tgo.tsx b/client/src/components/tgos/Tgo.tsx deleted file mode 100644 index e3e18d5e7..000000000 --- a/client/src/components/tgos/Tgo.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { - useOpenNewTgoPackageDialogMutation, - useOpenTgoInfoDialogMutation, -} from "../../api/liberationApi"; -import { Tgo as TgoModel } from "../../api/liberationApi"; -import SplitLines from "../splitlines/SplitLines"; -import { Icon, Point } from "leaflet"; -import { Symbol as MilSymbol } from "milsymbol"; -import { Marker, Tooltip } from "react-leaflet"; - -function iconForTgo(cp: TgoModel) { - const symbol = new MilSymbol(cp.sidc, { - size: 24, - }); - - return new Icon({ - iconUrl: symbol.toDataURL(), - iconAnchor: new Point(symbol.getAnchor().x, symbol.getAnchor().y), - }); -} - -interface TgoProps { - tgo: TgoModel; -} - -export default function Tgo(props: TgoProps) { - const [openNewPackageDialog] = useOpenNewTgoPackageDialogMutation(); - const [openInfoDialog] = useOpenTgoInfoDialogMutation(); - return ( - { - openInfoDialog({ tgoId: props.tgo.id }); - }, - contextmenu: () => { - openNewPackageDialog({ tgoId: props.tgo.id }); - }, - }} - > - - {`${props.tgo.name} (${props.tgo.control_point_name})`} -
- -
-
- ); -} diff --git a/client/src/components/tgos/index.ts b/client/src/components/tgos/index.ts deleted file mode 100644 index 3553f868c..000000000 --- a/client/src/components/tgos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Tgo"; diff --git a/client/src/components/tgoslayer/TgosLayer.tsx b/client/src/components/tgoslayer/TgosLayer.tsx deleted file mode 100644 index 8a12aacfd..000000000 --- a/client/src/components/tgoslayer/TgosLayer.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { selectTgos } from "../../api/tgosSlice"; -import { useAppSelector } from "../../app/hooks"; -import Tgo from "../tgos/Tgo"; -import { LayerGroup } from "react-leaflet"; - -interface TgosLayerProps { - categories?: string[]; - exclude?: true; -} - -export default function TgosLayer(props: TgosLayerProps) { - const allTgos = Object.values(useAppSelector(selectTgos).tgos); - const categoryFilter = props.categories ?? []; - const tgos = allTgos.filter( - (tgo) => categoryFilter.includes(tgo.category) === !(props.exclude ?? false) - ); - return ( - - {tgos.map((tgo) => { - return ; - })} - - ); -} diff --git a/client/src/components/tgoslayer/index.ts b/client/src/components/tgoslayer/index.ts deleted file mode 100644 index 282c0a83d..000000000 --- a/client/src/components/tgoslayer/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./TgosLayer"; diff --git a/client/src/components/threatzones/CoalitionThreatZones.tsx b/client/src/components/threatzones/CoalitionThreatZones.tsx deleted file mode 100644 index bf56a3e23..000000000 --- a/client/src/components/threatzones/CoalitionThreatZones.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ThreatZoneFilter, ThreatZonesLayer } from "./ThreatZonesLayer"; -import { LayersControl } from "react-leaflet"; - -interface CoalitionThreatZonesProps { - blue: boolean; -} - -export function CoalitionThreatZones(props: CoalitionThreatZonesProps) { - const color = props.blue ? "Blue" : "Red"; - return ( - <> - - - - - - - - - - - - - - ); -} diff --git a/client/src/components/threatzones/ThreatZone.tsx b/client/src/components/threatzones/ThreatZone.tsx deleted file mode 100644 index 506d36026..000000000 --- a/client/src/components/threatzones/ThreatZone.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { LatLng } from "../../api/liberationApi"; -import { Polygon } from "react-leaflet"; - -interface ThreatZoneProps { - poly: LatLng[][]; - blue: boolean; -} - -export default function ThreatZone(props: ThreatZoneProps) { - const color = props.blue ? "#0084ff" : "#c85050"; - return ( - - ); -} diff --git a/client/src/components/threatzones/ThreatZonesLayer.tsx b/client/src/components/threatzones/ThreatZonesLayer.tsx deleted file mode 100644 index fffa2e936..000000000 --- a/client/src/components/threatzones/ThreatZonesLayer.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { selectThreatZones } from "../../api/threatZonesSlice"; -import { useAppSelector } from "../../app/hooks"; -import ThreatZone from "./ThreatZone"; -import { LayerGroup } from "react-leaflet"; - -export enum ThreatZoneFilter { - FULL, - AIRCRAFT, - AIR_DEFENSES, - RADAR_SAMS, -} - -interface ThreatZonesLayerProps { - blue: boolean; - filter: ThreatZoneFilter; -} - -export function ThreatZonesLayer(props: ThreatZonesLayerProps) { - const allZones = useAppSelector(selectThreatZones).zones; - const zones = props.blue ? allZones.blue : allZones.red; - var filtered; - switch (props.filter) { - case ThreatZoneFilter.FULL: - filtered = zones.full; - break; - case ThreatZoneFilter.AIRCRAFT: - filtered = zones.aircraft; - break; - case ThreatZoneFilter.AIR_DEFENSES: - filtered = zones.air_defenses; - break; - case ThreatZoneFilter.RADAR_SAMS: - filtered = zones.radar_sams; - break; - } - return ( - - {filtered.map((poly, idx) => ( - - ))} - - ); -} diff --git a/client/src/components/threatzones/index.ts b/client/src/components/threatzones/index.ts deleted file mode 100644 index d0e929e48..000000000 --- a/client/src/components/threatzones/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { ThreatZonesLayer, ThreatZoneFilter } from "./ThreatZonesLayer"; -export { CoalitionThreatZones } from "./CoalitionThreatZones"; diff --git a/client/src/components/waypointdebugzones/HoldZones.tsx b/client/src/components/waypointdebugzones/HoldZones.tsx deleted file mode 100644 index 54bd6f194..000000000 --- a/client/src/components/waypointdebugzones/HoldZones.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { useGetDebugHoldZonesQuery } from "../../api/liberationApi"; -import { LayerGroup, Polygon, Polyline } from "react-leaflet"; - -interface HoldZonesProps { - flightId: string; -} - -function HoldZones(props: HoldZonesProps) { - const { data, error, isLoading } = useGetDebugHoldZonesQuery({ - flightId: props.flightId, - }); - - if (isLoading) { - return <>; - } - - if (error) { - console.error("Error while loading waypoint IP zone info", error); - return <>; - } - - if (!data) { - console.log("Waypoint IP zone returned empty response"); - return <>; - } - - return ( - <> - - - - - {data.excludedZones.map((zone, idx) => { - return ( - - ); - })} - - {data.permissibleZones.map((zone, idx) => { - return ( - - ); - })} - - {data.preferredLines.map((zone, idx) => { - return ( - - ); - })} - - ); -} - -interface HoldZonesLayerProps { - flightId: string | null; -} - -export function HoldZonesLayer(props: HoldZonesLayerProps) { - return ( - - {props.flightId ? : <>} - - ); -} diff --git a/client/src/components/waypointdebugzones/JoinZones.tsx b/client/src/components/waypointdebugzones/JoinZones.tsx deleted file mode 100644 index 476bc27e5..000000000 --- a/client/src/components/waypointdebugzones/JoinZones.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { useGetDebugJoinZonesQuery } from "../../api/liberationApi"; -import { LayerGroup, Polygon, Polyline } from "react-leaflet"; - -interface JoinZonesProps { - flightId: string; -} - -function JoinZones(props: JoinZonesProps) { - const { data, error, isLoading } = useGetDebugJoinZonesQuery({ - flightId: props.flightId, - }); - - if (isLoading) { - return <>; - } - - if (error) { - console.error("Error while loading waypoint join zone info", error); - return <>; - } - - if (!data) { - console.log("Waypoint join zone returned empty response"); - return <>; - } - - return ( - <> - - - - - {data.excludedZones.map((zone, idx) => { - return ( - - ); - })} - - {data.permissibleZones.map((zone, idx) => { - return ( - - ); - })} - - {data.preferredLines.map((zone, idx) => { - return ( - - ); - })} - - ); -} - -interface JoinZonesLayerProps { - flightId: string | null; -} - -export function JoinZonesLayer(props: JoinZonesLayerProps) { - return ( - - {props.flightId ? : <>} - - ); -} diff --git a/client/src/components/waypointdebugzones/WaypointDebugZonesControls.tsx b/client/src/components/waypointdebugzones/WaypointDebugZonesControls.tsx deleted file mode 100644 index 8c08f7f16..000000000 --- a/client/src/components/waypointdebugzones/WaypointDebugZonesControls.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { selectSelectedFlightId } from "../../api/flightsSlice"; -import { useAppSelector } from "../../app/hooks"; -import { HoldZonesLayer } from "./HoldZones"; -import { JoinZonesLayer } from "./JoinZones"; -import { LayersControl } from "react-leaflet"; - -const ENABLE_EXPENSIVE_DEBUG_TOOLS = false; - -export function WaypointDebugZonesControls() { - const selectedFlightId = useAppSelector(selectSelectedFlightId); - - if (!ENABLE_EXPENSIVE_DEBUG_TOOLS) { - return <>; - } - - return ( - <> - - - - - - - - ); -} diff --git a/client/src/components/waypointmarker/WaypointMarker.test.tsx b/client/src/components/waypointmarker/WaypointMarker.test.tsx deleted file mode 100644 index 5c66a12c5..000000000 --- a/client/src/components/waypointmarker/WaypointMarker.test.tsx +++ /dev/null @@ -1,277 +0,0 @@ -import { HTTP_URL } from "../../api/backend"; -import { renderWithProviders } from "../../testutils"; -import WaypointMarker, { TOOLTIP_ZOOM_LEVEL } from "./WaypointMarker"; -import { Map, Marker } from "leaflet"; -import { rest, MockedRequest, matchRequestUrl } from "msw"; -import { setupServer } from "msw/node"; -import React from "react"; -import { MapContainer } from "react-leaflet"; - -// https://mswjs.io/docs/extensions/life-cycle-events#asserting-request-payload -const waitForRequest = (method: string, url: string) => { - let requestId = ""; - - return new Promise((resolve, reject) => { - server.events.on("request:start", (req) => { - const matchesMethod = req.method.toLowerCase() === method.toLowerCase(); - const matchesUrl = matchRequestUrl(req.url, url).matches; - - if (matchesMethod && matchesUrl) { - requestId = req.id; - } - }); - - server.events.on("request:match", (req) => { - if (req.id === requestId) { - resolve(req); - } - }); - - server.events.on("request:unhandled", (req) => { - if (req.id === requestId) { - reject( - new Error(`The ${req.method} ${req.url.href} request was unhandled.`) - ); - } - }); - }); -}; - -const server = setupServer( - rest.post( - `${HTTP_URL}/waypoints/:flightId/:waypointIdx/position`, - (req, res, ctx) => { - if (req.params.flightId === "") { - return res(ctx.status(500)); - } - if (req.params.waypointIdx === "0") { - return res(ctx.status(403)); - } - return res(ctx.status(204)); - } - ) -); - -beforeAll(() => server.listen({ onUnhandledRequest: "error" })); -afterEach(() => server.resetHandlers()); -afterAll(() => server.close()); - -describe("WaypointMarker", () => { - it("is placed in the correct location", () => { - const waypoint = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "", - }; - const marker = React.createRef(); - renderWithProviders( - - - - ); - expect(marker.current?.getLatLng()).toEqual({ lat: 0, lng: 0 }); - }); - - it("tooltip is hidden when zoomed out", () => { - const waypoint = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "", - }; - const map = React.createRef(); - const marker = React.createRef(); - renderWithProviders( - - - - ); - map.current?.setView({ lat: 0, lng: 0 }, TOOLTIP_ZOOM_LEVEL - 1); - expect(marker.current?.getTooltip()?.isOpen()).toBeFalsy(); - }); - - it("tooltip is shown when zoomed in", () => { - const waypoint = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 0, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "", - }; - const map = React.createRef(); - const marker = React.createRef(); - renderWithProviders( - - - - ); - map.current?.setView({ lat: 0, lng: 0 }, TOOLTIP_ZOOM_LEVEL); - expect(marker.current?.getTooltip()?.isOpen()).toBeTruthy(); - }); - - it("tooltip has correct contents", () => { - const waypoint = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 25000, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "09:00:00", - }; - const map = React.createRef(); - const marker = React.createRef(); - renderWithProviders( - - - - ); - expect(marker.current?.getTooltip()?.getContent()).toEqual( - "0
25000 ft MSL
09:00:00" - ); - }); - - it("resets the tooltip while dragging", () => { - const waypoint = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 25000, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "09:00:00", - }; - const marker = React.createRef(); - renderWithProviders( - - - - ); - marker.current?.fireEvent("dragstart"); - expect(marker.current?.getTooltip()?.getContent()).toEqual( - "Waiting to recompute TOT..." - ); - }); - - it("sends the new position to the backend on dragend", async () => { - const departure = { - name: "", - position: { lat: 0, lng: 0 }, - altitude_ft: 25000, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "09:00:00", - }; - const waypoint = { - name: "", - position: { lat: 1, lng: 1 }, - altitude_ft: 25000, - altitude_reference: "MSL", - is_movable: false, - should_mark: false, - include_in_path: true, - timing: "09:00:00", - }; - const flight = { - id: "1234", - blue: true, - sidc: "", - waypoints: [departure, waypoint], - }; - const marker = React.createRef(); - - // There is no observable UI change from moving a waypoint, just a message - // to the backend to record the frontend change. The real backend will then - // push an updated game state which will update redux, but that's not part - // of this component's behavior. - const pendingRequest = waitForRequest( - "POST", - `${HTTP_URL}/waypoints/1234/1/position` - ); - - renderWithProviders( - - - - - ); - - marker.current?.fireEvent("dragstart"); - marker.current?.fireEvent("dragend", { target: marker.current }); - - const request = await pendingRequest; - const response = await request.json(); - expect(response).toEqual({ lat: 1, lng: 1 }); - }); -}); diff --git a/client/src/components/waypointmarker/WaypointMarker.tsx b/client/src/components/waypointmarker/WaypointMarker.tsx deleted file mode 100644 index 8b33b757f..000000000 --- a/client/src/components/waypointmarker/WaypointMarker.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { - Flight, - Waypoint, - useSetWaypointPositionMutation, -} from "../../api/liberationApi"; -import mergeRefs from "../../mergeRefs"; -import { Icon } from "leaflet"; -import { Marker as LMarker } from "leaflet"; -import icon from "leaflet/dist/images/marker-icon.png"; -import iconShadow from "leaflet/dist/images/marker-shadow.png"; -import { - ForwardedRef, - MutableRefObject, - forwardRef, - useCallback, - useEffect, - useRef, -} from "react"; -import { Marker, Tooltip, useMap, useMapEvent } from "react-leaflet"; - -export const TOOLTIP_ZOOM_LEVEL = 9; - -const WAYPOINT_ICON = new Icon({ - iconUrl: icon, - shadowUrl: iconShadow, - iconAnchor: [12, 41], -}); - -interface WaypointMarkerProps { - number: number; - waypoint: Waypoint; - flight: Flight; -} - -const WaypointMarker = forwardRef( - (props: WaypointMarkerProps, ref: ForwardedRef) => { - // Most props of react-leaflet types are immutable and components will not - // update to account for changes, so we can't simply use the `permanent` - // property of the tooltip to control tooltip visibility based on the zoom - // level. - // - // On top of that, listening for zoom changes and opening/closing is not - // sufficient because clicking anywhere will close any opened tooltips (even - // if they are permanent; once openTooltip has been called that seems to no - // longer have any effect). - // - // Instead, listen for zoom changes and rebind the tooltip when the zoom level - // changes. - const map = useMap(); - const marker: MutableRefObject = useRef(null); - - const [putDestination] = useSetWaypointPositionMutation(); - - const rebindTooltip = useCallback(() => { - if (marker.current === null) { - return; - } - - const tooltip = marker.current.getTooltip(); - if (tooltip === undefined) { - return; - } - - const permanent = map.getZoom() >= TOOLTIP_ZOOM_LEVEL; - marker.current - .unbindTooltip() - .bindTooltip(tooltip, { permanent: permanent }); - }, [map]); - useMapEvent("zoomend", rebindTooltip); - - useEffect(() => { - const waypoint = props.waypoint; - marker.current?.setTooltipContent( - `${props.number} ${waypoint.name}
` + - `${waypoint.altitude_ft.toFixed()} ft ${ - waypoint.altitude_reference - }
` + - waypoint.timing - ); - }); - - const waypoint = props.waypoint; - return ( - { - const m: LMarker = e.target; - m.setTooltipContent("Waiting to recompute TOT..."); - }, - dragend: async (e) => { - const m: LMarker = e.target; - const destination = m.getLatLng(); - try { - await putDestination({ - flightId: props.flight.id, - waypointIdx: props.number, - leafletPoint: { lat: destination.lat, lng: destination.lng }, - }); - } catch (e) { - console.error("Failed to set waypoint position", e); - } - }, - }} - ref={mergeRefs(ref, marker)} - > - - - ); - } -); - -export default WaypointMarker; diff --git a/client/src/components/waypointmarker/index.ts b/client/src/components/waypointmarker/index.ts deleted file mode 100644 index e0797a71c..000000000 --- a/client/src/components/waypointmarker/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import WaypointMarker from "./WaypointMarker"; - -export default WaypointMarker; diff --git a/client/src/hooks/useEventSteam.ts b/client/src/hooks/useEventSteam.ts deleted file mode 100644 index 2c6d74072..000000000 --- a/client/src/hooks/useEventSteam.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { handleStreamedEvents } from "../api/eventstream"; -import { useAppDispatch } from "../app/hooks"; -import { useSocket } from "./useSocket"; -import { useCallback, useEffect } from "react"; - -export const useEventStream = () => { - const ws = useSocket(); - const dispatch = useAppDispatch(); - - const onMessage = useCallback( - (message: MessageEvent) => { - handleStreamedEvents(dispatch, JSON.parse(message.data)); - }, - [dispatch] - ); - - useEffect(() => { - ws.addEventListener("message", onMessage); - return () => { - ws.removeEventListener("message", onMessage); - }; - }); -}; - -export default useEventStream; diff --git a/client/src/hooks/useInitialGameState.tsx b/client/src/hooks/useInitialGameState.tsx deleted file mode 100644 index a10dfa52f..000000000 --- a/client/src/hooks/useInitialGameState.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import reloadGameState from "../api/gamestate"; -import { useAppDispatch } from "../app/hooks"; -import { useEffect } from "react"; - -// TODO: This should probably be distinct useControlPoints, useFlights, etc that -// are smart enough to only initialize once which get called in the components -// that use them rather than forcibly loading the whole game in the root -// component. -export const useInitialGameState = () => { - const dispatch = useAppDispatch(); - useEffect(() => { - reloadGameState(dispatch); - }); -}; - -export default useInitialGameState; diff --git a/client/src/hooks/useSocket.ts b/client/src/hooks/useSocket.ts deleted file mode 100644 index 06176bb35..000000000 --- a/client/src/hooks/useSocket.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SocketContext } from "../components/socketprovider/socketprovider"; -import { useContext } from "react"; - -export const useSocket = () => { - const socket = useContext(SocketContext); - - return socket; -}; diff --git a/client/src/index.css b/client/src/index.css deleted file mode 100644 index 4a1df4db7..000000000 --- a/client/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; -} diff --git a/client/src/index.tsx b/client/src/index.tsx deleted file mode 100644 index 2ea260f77..000000000 --- a/client/src/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import App from "./App"; -import { setupStore } from "./app/store"; -import { SocketProvider } from "./components/socketprovider/socketprovider"; -import "./index.css"; -import * as serviceWorker from "./serviceWorker"; -import React from "react"; -import ReactDOM from "react-dom/client"; -import { Provider } from "react-redux"; - -const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement -); -root.render( - - - - - - - -); - -// If you want your app to work offline and load faster, you can change -// unregister() to register() below. Note this comes with some pitfalls. -// Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); diff --git a/client/src/logo.svg b/client/src/logo.svg deleted file mode 100644 index 84667388c..000000000 --- a/client/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/client/src/mergeRefs.test.tsx b/client/src/mergeRefs.test.tsx deleted file mode 100644 index b95aa5bef..000000000 --- a/client/src/mergeRefs.test.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import mergeRefs from "./mergeRefs"; - -describe("mergeRefs", () => { - it("merges all kinds of refs", () => { - const referent = "foobar"; - const ref = { current: null }; - var callbackResult = null; - const callbackRef = (node: string | null) => { - if (node != null) { - callbackResult = node; - } - }; - mergeRefs(ref, callbackRef)(referent); - expect(callbackResult).toEqual("foobar"); - expect(ref.current).toEqual("foobar"); - }); -}); diff --git a/client/src/mergeRefs.ts b/client/src/mergeRefs.ts deleted file mode 100644 index a75fda766..000000000 --- a/client/src/mergeRefs.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ForwardedRef } from "react"; - -const mergeRefs = (...refs: ForwardedRef[]) => { - return (node: T) => { - for (const ref of refs) { - if (ref == null) { - } else if (typeof ref === "function") { - ref(node); - } else { - ref.current = node; - } - } - }; -}; - -export default mergeRefs; diff --git a/client/src/react-app-env.d.ts b/client/src/react-app-env.d.ts deleted file mode 100644 index 6431bc5fc..000000000 --- a/client/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/client/src/serviceWorker.ts b/client/src/serviceWorker.ts deleted file mode 100644 index e7b8199e2..000000000 --- a/client/src/serviceWorker.ts +++ /dev/null @@ -1,146 +0,0 @@ -// This optional code is used to register a service worker. -// register() is not called by default. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the -// existing tabs open on the page have been closed, since previously cached -// resources are updated in the background. - -// To learn more about the benefits of this model and instructions on how to -// opt-in, read https://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === "localhost" || - // [::1] is the IPv6 localhost address. - window.location.hostname === "[::1]" || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -type Config = { - onSuccess?: (registration: ServiceWorkerRegistration) => void; - onUpdate?: (registration: ServiceWorkerRegistration) => void; -}; - -export function register(config?: Config) { - if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener("load", () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://bit.ly/CRA-PWA" - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); - } -} - -function registerValidSW(swUrl: string, config?: Config) { - navigator.serviceWorker - .register(swUrl) - .then((registration) => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker == null) { - return; - } - installingWorker.onstatechange = () => { - if (installingWorker.state === "installed") { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - "New content is available and will be used when all " + - "tabs for this page are closed. See https://bit.ly/CRA-PWA." - ); - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration); - } - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log("Content is cached for offline use."); - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration); - } - } - } - }; - }; - }) - .catch((error) => { - console.error("Error during service worker registration:", error); - }); -} - -function checkValidServiceWorker(swUrl: string, config?: Config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl, { - headers: { "Service-Worker": "script" }, - }) - .then((response) => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get("content-type"); - if ( - response.status === 404 || - (contentType != null && contentType.indexOf("javascript") === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then((registration) => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); - } - }) - .catch(() => { - console.log( - "No internet connection found. App is running in offline mode." - ); - }); -} - -export function unregister() { - if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready - .then((registration) => { - registration.unregister(); - }) - .catch((error) => { - console.error(error.message); - }); - } -} diff --git a/client/src/setupTests.ts b/client/src/setupTests.ts deleted file mode 100644 index 5fdf00169..000000000 --- a/client/src/setupTests.ts +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import "@testing-library/jest-dom/extend-expect"; diff --git a/client/src/testutils/index.tsx b/client/src/testutils/index.tsx deleted file mode 100644 index 64196f3e0..000000000 --- a/client/src/testutils/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -// https://redux.js.org/usage/writing-tests -import { setupStore } from "../app/store"; -import type { AppStore, RootState } from "../app/store"; -import type { PreloadedState } from "@reduxjs/toolkit"; -import { render } from "@testing-library/react"; -import type { RenderOptions } from "@testing-library/react"; -import React, { PropsWithChildren } from "react"; -import { Provider } from "react-redux"; - -// This type interface extends the default options for render from RTL, as well -// as allows the user to specify other things such as initialState, store. -interface ExtendedRenderOptions extends Omit { - preloadedState?: PreloadedState; - store?: AppStore; -} - -export function renderWithProviders( - ui: React.ReactElement, - { - preloadedState = {}, - // Automatically create a store instance if no store was passed in - store = setupStore(preloadedState), - ...renderOptions - }: ExtendedRenderOptions = {} -) { - function Wrapper({ children }: PropsWithChildren<{}>): JSX.Element { - return {children}; - } - return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) }; -} diff --git a/client/tsconfig.json b/client/tsconfig.json deleted file mode 100644 index a841e1dfc..000000000 --- a/client/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noFallthroughCasesInSwitch": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx" - }, - "include": [ - "src" - ] -} diff --git a/codecov.yaml b/codecov.yaml deleted file mode 100644 index ea2cdd762..000000000 --- a/codecov.yaml +++ /dev/null @@ -1,8 +0,0 @@ -coverage: - status: - patch: - default: - informational: true - project: - default: - informational: true diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index c39fd1976..000000000 --- a/docs/conf.py +++ /dev/null @@ -1,34 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -project = "DCS Liberation" -copyright = "2023, DCS Liberation Team" -author = "DCS Liberation Team" -release = "11.0.0" - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -extensions = [ - "myst_parser", - "sphinx_rtd_theme", - "sphinx.ext.autosectionlabel", - "sphinx.ext.todo", -] - -templates_path = ["_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -html_theme = "sphinx_rtd_theme" -html_static_path = ["_static"] - -todo_include_todos = True diff --git a/docs/dev/design/index.rst b/docs/dev/design/index.rst deleted file mode 100644 index 51f319edf..000000000 --- a/docs/dev/design/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Design docs -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - turnless.md diff --git a/docs/dev/design/turnless.md b/docs/dev/design/turnless.md deleted file mode 100644 index edd832d5c..000000000 --- a/docs/dev/design/turnless.md +++ /dev/null @@ -1,180 +0,0 @@ -# Turnless Campaign - -This outlines a path for us converting Liberation from turn based into a -turnless campaign game like BMS. - -## Hard problems - -### We can't simulate combat - -We can't feasibly simulate the details of combat, nor can we generate a mission -mid-engagement. The mission editor does not support generating aircraft -mid-maneuver, or with any SA. - -To avoid that problem, instead of simulating the combat we put the group in a -"freeze" at the moment the engagement begins. Any frozen groups are spawned -wherever they were frozen so simulation can be deferred to DCS. Each freeze will -have a deadline for completion, at which point a simple strength-based -autoresolve will take place. - -After a frozen engagement is resolved (whether in sim or automatically), if the -mission objective has not been achieved a mission abort will be evaluated. - -### We don't know where the roads are - -We don't know where the in-game roads are, so we can't precisely simulate the -location of convoys as they move, nor the amount of time they will take to move -between bases. - -Time can be solved by just having the campaign designer encode the travel time -in the campaign. The ME will estimate it for them so it’s simple to do. Spawn -locations cannot be made precise, but we can have campaign designers define -several waypoints along the route and spawn the convoy at the most appropriate -one. - -### SAM engagement zones are huge - -The large threat zone of many SAMs would cause most of the map to be a frozen -engagement. - -To avoid that, SAMs will not cause frozen engagements, but will be simulated at -a basic level. Each SAM will track a group, and when in range will periodically -“shoot”, and those shots will have a chance to kill an aircraft in the targeted -group. - -## Systems that need to change - -### AI Commander - -Theater state tracking for the HTN becomes much more complicated since it needs -to always be able to replan based on pending plans. This shouldn't be too bad -since RndName's PR did similar and the plan to continue that should work here. -The commander needs to learn to abort missions that are no longer viable. - -### Transports - -With turns gone, transports can longer move one link per turn. See the entry in -"hard problems" above. To begin with we can pick an arbitrary time per link and -just always spawn the transport at the origin regardless of where they ought to -be. - -### Turn based systems - -A number of systems that act in a number of turns become time based: - -- Runway repair -- Unit delivery -- Weather changes -- Pilot replenishment -- Income - -Procurement could be made simpler if we do away with cash in favor of fixed -replenishment rates. - -### Front line advancement - -Front line combat is happening continuously so we need to simulate its movement -and losses on the front line. - -### Mission generation - -The mission generator needs to be able to generate aircraft in specific -locations, with partial fuel, and possibly with some weapons expended. - -### Mission result processing - -Last known positions need to be recorded, as do weapon inventory and fuel -states. - -### UI - -Frozen combats need to be immutable to the player. - -Missions in progress need to be made cancelable. - -The map needs to show the locations of in-progress missions, including frozen -engagements. - -There needs to be a UI to examine frozen engagements. - -## Roadmap - -This roadmap is ordered so that we can attempt to make this change in phases -that may take more than a single release. It is not focused on providing the -best gameplay experience ASAP, but on being able to approach this gradually -rather than freezing all other development or branching and a painful merge. - -### Front-line progress rework - -Add auto-resolve for the front line, adjust progress estimates based on stances -and not just kills (an enemy in retreat is less likely to be killed, but still -gives up ground). - -### Add play from first-contact option - -Add simulation of the mission from the start of the turn up to the first -engagement. Generate the mission from that point. - -### Add fuel expenditure estimation for travel to start location - -Adjust fuel quantities at the start of the mission to account for travel. - -### Add UI to display simulation to first contact - -Before removing turns, add play/pause buttons to the game that will simulate the -mission up to the first engagement. Once play is pressed no changes may be made -to the ATO. - -When the turn ends it behaves like the normal end of turn. The ATO is reset and -the new turn is planned. - -### Add mission abort option for players - -Add the option to abort flight and packages for players. The AI won’t use this -yet but it will be needed once engagement simulation is added. - -### Add simulation for frozen combats - -Allows play to proceed through engagements. The AI will abort missions that are -unlikely to succeed after each combat is resolved. - -### Estimate fuel/weapon use simulation for frozen combats - -Improve behavior for groups that have completed an auto-resolved combat by -estimating their fuel and ammo use. This could be used to check if the mission -should be aborted. - -### Add player options to create new packages after pressing play - -Allow players to create new flights as the mission simulates. This would be the -most effective way to add intercept missions. - -### Make planning real-time - -Make the AI planner periodically reevaluate missions to add to the ATO. It will -still plan as many missions as possible up front so that the DCS side of the -mission can run as long as possible, but it could make use of aircraft that had -aborted or returned. - -### Time-based systems instead of turn based - -Move the systems that are currently based on turns to be based on duration. Each -turn is assumed to be six hours since there are four turns in a day. - -### Time between turns based on mission duration - -Change the turn duration to be based on the length of the mission played. - -### Track end positions of aircraft, remove turns - -If we can track the status of missions after the simulation ends we can continue -where we left off. Do that, and remove the concept of turns. - -### Track ammo/fuel status of aircraft at the end of the mission - -Improve post-simulation realism by tracking the ammunition and fuel spent. - -### Add turnaround times for landed aircraft - -Once aircraft returning from a mission land, a timer starts to track the -turnaround time before they'll be ready to redeploy as opposed to being instant. \ No newline at end of file diff --git a/docs/dev/index.rst b/docs/dev/index.rst deleted file mode 100644 index 13be505a5..000000000 --- a/docs/dev/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -Developer documentation -======================= - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - design/index.rst diff --git a/docs/game/index.rst b/docs/game/index.rst deleted file mode 100644 index 0134d46c0..000000000 --- a/docs/game/index.rst +++ /dev/null @@ -1,6 +0,0 @@ -Manual -====== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index e842bce26..000000000 --- a/docs/index.rst +++ /dev/null @@ -1,16 +0,0 @@ -DCS Liberation -============== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - game/index.rst - modding/index.rst - dev/index.rst - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 954237b9b..000000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/modding/fuel-consumption-measurement.md b/docs/modding/fuel-consumption-measurement.md deleted file mode 100644 index 62dd0a1b3..000000000 --- a/docs/modding/fuel-consumption-measurement.md +++ /dev/null @@ -1,80 +0,0 @@ -# Measuring estimated fuel consumption - -To estimate fuel consumption numbers for an aircraft, create a mission with a -typical heavy load for the aircraft. For example, to measure for the F/A-18C, a -loadout with two bags, two GBU-31s, two sidewinders, an AMRAAM, and an ATFLIR. -Do **not** drop bags or weapons during the test flight. - -Start the aircraft on the ground at a large airport (for example, Akrotiri) at a -parking space at the opposite end of the takeoff runway so you can estimate long -taxi fuel consumption. - -When you enter the jet, note the amount of fuel below, then taxi to the far end -of the runway. Hold short and note the remaining fuel below. - -Follow a typical takeoff pattern for the aircraft. For the F/A-18C, this might -be AB takeoff, reduce to MIL at 350KIAS, and maintian 350KIAS/0.85 mach until -cruise altitude (angles 25). - -Once you reach angels 25, pause the game. Note your remaining fuel below and -measure the distance traveled from takeoff. Mark your location on the map. - -Level out and increase to cruise speed if needed. Liberation assumes 0.85 mach -for supersonic aircraft, for subsonic aircraft it depends so pick something -reasonable and note your descision in a comment in the file when done. Maintain -speed, heading, and altitude for a long distance (the longer the distance, the -more accurate the result, but be careful to leave enough fuel for the final -section). Once complete, note the distance traveled and the remaining fuel. - -Finally, increase speed as you would for an attack. At least MIL power, -potentially use AB sparingly, etc. The goal is to measure fuel consumption per -mile traveled during an attack run. - -``` -start: -taxi end: -to 25k distance: -at 25k fuel: -cruise (.85 mach) distance: -cruise (.85 mach) end fuel: -combat distance: -combat end fuel: -``` - -Finally, fill out the data in the aircraft data. Below is an example for the -F/A-18C: - -``` -start: 15290 -taxi end: 15120 -climb distance: 40NM -at 25k fuel: 13350 -cruise (.85 mach) distance: 100NM -cruise (.85 mach) end fuel: 11140 -combat distance: 100NM -combat end fuel: 8390 - -taxi = start - taxi end = 15290 - 15120 = 170 -climb fuel = taxi end - at 25k fuel = 15120 - 13350 = 1770 -climb ppm = climb fuel / climb distance = 1770 / 40 = 44.25 -cruise fuel = at 25k fuel - cruise end fuel = 13350 - 11140 = 2210 -cruise ppm = cruise fuel / cruise distance = 2210 / 100 = 22.1 -combat fuel = cruise end fuel - combat end fuel = 11140 - 8390 = 2750 -combat ppm = combat fuel / combat distance = 2750 / 100 = 27.5 -``` - -```yaml -fuel: - # Parking A1 to RWY 32 at Akrotiri. - taxi: 170 - # AB takeoff to 350/0.85, reduce to MIL and maintain 350 to 25k ft. - climb_ppm: 44.25 - # 0.85 mach for 100NM. - cruise_ppm: 22.1 - # ~0.9 mach for 100NM. Occasional AB use. - combat_ppm: 27.5 - min_safe: 2000 -``` - -The last entry (`min_safe`) is the minimum amount of fuel that the aircraft -should land with. diff --git a/docs/modding/images/ground_object_buy_menu.png b/docs/modding/images/ground_object_buy_menu.png deleted file mode 100644 index 57f6d519b..000000000 Binary files a/docs/modding/images/ground_object_buy_menu.png and /dev/null differ diff --git a/docs/modding/images/layout_miz_example.png b/docs/modding/images/layout_miz_example.png deleted file mode 100644 index e227e7267..000000000 Binary files a/docs/modding/images/layout_miz_example.png and /dev/null differ diff --git a/docs/modding/images/layouts.png b/docs/modding/images/layouts.png deleted file mode 100644 index 56d67c9a4..000000000 Binary files a/docs/modding/images/layouts.png and /dev/null differ diff --git a/docs/modding/index.rst b/docs/modding/index.rst deleted file mode 100644 index 645f2c068..000000000 --- a/docs/modding/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Modding guide -============= - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - fuel-consumption-measurement.md - layouts.rst - weather.rst diff --git a/docs/modding/layouts.rst b/docs/modding/layouts.rst deleted file mode 100644 index 1239d026d..000000000 --- a/docs/modding/layouts.rst +++ /dev/null @@ -1,397 +0,0 @@ -The Layout System -================= - -.. note:: - The documentation of the layout system is still WIP and not - complete as the development of this feature involves a major refactoring - of the base code. Therefore this documentation is currently used for - development purpose primarily. The documentation will be updated soon. - Any help in updating this wiki page is appreciated! - -The Layout System is a new way of defining how ground objects like SAM -Sites or other Vehicle / Ship Groups will be generated (which type of -units, how many units, alignment and orientation). It is a complete -rework of the previous generator-based logic which was written in python -code. The new system allows to define layouts with easy to write yaml -code and the use of the DCS Mission Editor for easier placement of the -units. The layout system also introduced a new logical grouping of Units -and layouts for them, the Armed Forces, which will allow major -improvements to the Ground Warfare in upcoming features. - -**Armed Forces** - -The Armed Forces is a new system introduced with the layout system which will -allow to identitfy and group possible units from the faction together with -available layouts for these groups. It is comparable to the AirWing and Squadron -implementation but just for Ground and Naval Forces. All possible Force Groups -(grouping of 1 or more units and and the available layouts for them) will be -generated during campaign initialization and will be used later by many -different systems. A Force Group can also include static objects which was not -possible before the introduction of the layout system. It is also possible to -define presets of these Force Groups within the faction file which is handy for -more complex groups like a SA-10 Battery or similar. Example: `SA-10.yaml`_. -which includes all the units like SR, TR, LN and has the layout of a -`S-300_Site.yaml`_. - -.. _SA-10.yaml: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/groups/SA-10.yaml -.. _S-300_Site.yaml: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/layouts/anti_air/S-300_Site.yaml - -**The Layout System** - -In the previous system the generator which created the ground object was written -in python which made modifications and reusability very complicated. To allow -easier handling of the layouts and decoupling of alignment of units and the -actual unit type (for example Ural-375) the layout system was introduced. -Previously we had a generator for every different SAM Site, now we can just -reuse the alignemnt (e.g. 6 Launchers in a circle alignment) for multiple SAM -Systems and introduce more variety. - -This new System allows Users and Designers to easily create or modify -layouts as the new alginment and orientation of units is defined with -the DCS Mission editor. An additional .yaml file allows the -configuration of the layout with settings like allow unit types or -random amounts of units. In total the new system reduces the complexity -and allows to precisely align / orient units as needed and create -realistic looking ground units. - -As the whole ground unit generation and handling was reworked it is now -also possible to add static units to a ground object, so even -Fortifcation or similar can be added to templates in the future. - -General Concept -~~~~~~~~~~~~~~~ - -.. figure:: images/layouts.png - :alt: Overview - - Overview - -All possible Force Groups will be generated during campaign -initialization by checking all possible units for the specific faction -and all available layouts. The code will automatically match general -layouts with available units. It is also possible to define preset -groups within the faction files which group many units and the prefered -layouts for the group. This is especially handy for unique layouts which -are not defined as ``global``. For example complex sam sites like the -S-300 or Patriot which have very specific alignment of the different -units. - -Layouts will be matched to units based on the special definition given -in the corresponding yaml file. For example a layout which is defined as -global and allows the unit_class SHORAD will automatically be used for -all available SHORAD units which are defined in the faction file. - -.. todo:: Describe the optional flag. - -All these generated ForceGroups will be managed by the ArmedForces class -of the specific coalition. This class will be used by other parts of the -system like the start_generator or the BuyMenu. The ArmedForces class -will then generate the TheaterGroundObject which will be used by -liberation. - -Example for a customized Ground Object Buy Menu which makes use of -Templates and UnitGroups: - -.. figure:: images/ground_object_buy_menu.png - :alt: Ground object buy menu - - Ground object buy menu - -How to modify or add layouts ----------------------------- - -.. warning:: - Whenever changes were made to layouts they have to be re-imported into - Liberation. See :ref:`Import Layouts into Liberation`. - -A layout consists of two special files: - -- layout.miz which defines the actual positioning and alignment of the - groups / units -- layout.yaml which defines the necessary information like amount of - units, possible types or classes. - -To add a new template a new yaml has to be created as every yaml can -only define exact one template. Best practice is to copy paste an -existing template which is similar to the one to be created as starting -point. The next step is to create a new .miz file and align Units and -statics to the wishes. Even if existing ones can be reused, best -practice is to always create a fresh one to prevent side effects. The -most important part is to use a new Group for every different Unit Type. -It is not possible to mix Unit Types in one group within a template. For -example it is not possible to have a logistic truck and a AAA in the -same group. The miz file will only be used to get the exact position and -orientation of the units, therefore it is irrelevant which type of unit -will be used. The unit type will be later defined inside the yaml file. -For the next step all Group names have to be added to the yaml file. -Take care to that these names match exactly! Assign the unit_types or -unit_classes properties to math the needs. - -The Layout miz -~~~~~~~~~~~~~~ - -The miz file is used to define the positioning and orientation of the -different units for the template. The actual unit which is used is -irrelevant. It is important to use a unique and meaningful name for the -groups as this will be used in the yaml file as well. The information -which will be extracted from the miz file are just the coordinates and -heading of the units. - -*Important*: Every different unit type has to be in a separate Group for -the template to work. You can not add units of different types to the -same group. They can get merged back together during generation by -setting the group property. In the example below both groups -``AAA Site 0`` and ``AAA Site 1`` have the group = 1 which means that -they will be in the same dcs group during generation. - -*Important*: Liberation expects every template to be designed with an -orientation of heading 0 (North) in mind. The complete GroundObject will -during the campaign generation process be rotated to match the -orientation defined by the campaign designer. If the layout was not -created with an orientation of heading 0 the later generated -GroundObject will likely be misaligned and not work properly. - -.. todo:: - max amount of possible units is defined from the miz. Example if later the - group should have 6 units than there have to be 6 defined in the miz. - -.. figure:: images/layout_miz_example.png - :alt: Example template mission - - Example template mission - -The Layout configuration file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. todo:: Description about the layout yaml file. - -Possible Information: - -.. list-table:: - :header-rows: 1 - - * - Property - - Type - - Required - - Description - - Example - * - name - - ``str`` - - Yes - - A name to identify the template - - .. code:: yaml - - name: Armor Group - * - tasks - - list of ``GroupTask`` - - Yes - - A list of tasks which the template can fulfill - - .. code:: yaml - - tasks: - - AAA - - SHORAD - * - generic - - ``bool``, default false - - No - - True if this template will be used to create general ``UnitGroups`` - - - * - description - - ``str`` - - No - - Short description of the template - - - * - groups - - List of ``Groups`` - - Yes - - See below for definition of a group - - - * - layout_file - - ``str`` - - No - - The .miz file which has the groups/units of the layout included. Only - needed if the file has a different name than the yaml file - - .. code:: yaml - - layout_file: resources/layouts/naval/legacy_naval_templates.miz - -.. todo:: Group and SubGroup - -A group has 1..N sub groups. The name of the Group will be used later -within the DCS group name. - -All SubGroups will be merged into one DCS Group - -Every unit type has to be defined as a sub group as following: - -.. list-table:: - :header-rows: 1 - - * - Property - - Type - - Required - - Description - * - name - - ``str`` - - Yes - - The group name used in the .miz. Must match exactly! - * - optional - - ``bool``, default: false - - No - - Defines wether the layout can be used without this group if the faction - has no access to the unit type or the user wants to disable this group - * - fill - - ``bool``, default: false - - No - - If the group is optional the layout is used from a PresetGroup this - property tells the system if it should use any possible faction - accessible unit to fill up this slot if no capable one was defined in - the preset yaml. - * - unit_count - - list of ``int`` - - No - - Amount of units to be generated for this group. Can be fixed or a range - where it will be picked randomly - * - unit_types - - list of DCS unit type IDs - - No - - Specific unit_types for ground units. Complete list from `vehicles.py`_. - This list is extended by all supported mods! - * - unit_classes - - list of unit classes - - No - - Unit classes of supported units. Defined by ``UnitClass`` in - `game/data/units.py`_. - * - statics - - list of static types - - No - - Specific unit_types of statics. Complete list from `statics.py`_ - -.. _vehicles.py: https://github.com/pydcs/dcs/blob/master/dcs/vehicles.py -.. _game/data/units.py: https://github.com/dcs-liberation/dcs_liberation/blob/develop/game/data/units.py -.. _statics.py: https://github.com/pydcs/dcs/blob/master/dcs/statics.py - -Complete example of a generic template for an Aircraft Carrier group: - -.. code:: yaml - - name: Carrier Group - generic: true - tasks: - - AircraftCarrier - groups: - - Carrier: # Group Name of the DCS Group - - name: Carrier Group 0 # Sub Group used in the layout.miz - unit_count: - - 1 - unit_classes: - - AircraftCarrier - - Escort: # Group name of the 2nd Group - - name: Carrier Group 1 - unit_count: - - 4 - unit_classes: - - Destroyer - layout_file: resources/layouts/naval/legacy_naval_templates.miz - -Import Layouts into Liberation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For performance improvements all layouts are serialized to a so called -pickle file inside the save folder defined in the liberation -preferences. Every time changes are made to the layouts this file has to -be recreated. It can be recreated by either deleting the layouts.p file -manually or using the special option in the Liberation Toolbar -(Developer Tools -> Import Layouts). It will also be recreated after -each Liberation update as it will check the Version Number and recreate -it when changes are recognized. - -Migration from Generators -------------------------- - -The previous generators were migrated using a script which build a group using -the generator. All of these groups were save into one .miz file -`original_generator_layouts.miz`_. This miz file can be used to verify the -templates and to generalize similar templates to decouple the layout from the -actual units. As this is a time-consuming and sphisticated task this will be -done over time. With the first step the technical requirements will be fulfilled -so that the generalization can happen afterwards the technical pr gets merged. - -.. _original_generator_layouts.miz: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/layouts/original_generator_layouts.miz - -Updates for Factions -~~~~~~~~~~~~~~~~~~~~ - -With the rework there were also some changes to the faction file -definitions. Older faction files can not be loaded anymore and have to -be adopted to the new changes. During migration all default factions -were automatically updated, so they will work out of the box. - -You can find more detailed information about how to customize the -faction file in `Custom factions`_. - -What was changed: - -* Removed the ``ewrs`` list. All EWRs are now defined in the list - ``air_defense_units``. -* Added the ``air_defense_units`` list. All units with the Role AntiAir can be - defined here as `GroundUnitType`_. All possible units are defined in - `resources/units/ground_units`_. -* Added ``preset_groups``. This list allows to define Preset Groups (described - above) like SAM Systems consisting of Launcher, SR, TR and so on instead of - adding them each to “air_defense_units”. The presets are defined in - `resources/groups`_ -* Migrated ``air_defenses`` to air_defense_units and preset_sets. -* ``Missiles`` are migrated to GroundUnitTypes instead of Generator names (see - air_defense_units for how to use) -* Removed ``cruisers``, ``destroyers`` and ``naval_generators``. Migrated them - to naval_units and preset_groups -* Added ``naval_units`` with the correct ship name found in - `resources/units/ships`_. -* ``aircraft_carrier`` and ``helicopter_carrier`` were moved to ``naval_units`` - as well. - -.. _Custom factions: https://github.com/dcs-liberation/dcs_liberation/wiki/Custom-Factions -.. _GroundUnitType: https://github.com/dcs-liberation/dcs_liberation/blob/develop/game/dcs/groundunittype.py -.. _resources/units/ground_units: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/units/ground_units -.. _resources/units/ships: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/units/ships -.. _resources/groups: https://github.com/dcs-liberation/dcs_liberation/blob/develop/resources/groups - -Preset Groups -------------- - -Instead of adding the exact name of the previous generator to add -complex groups like SAM sites or similar to the faction it is now -possible to add preset groups to the faction file. As described earlier -such a preset group (Force Group) can be defined very easy with a yaml -file. This file allows to define the name, tasking, units, statics and -the prefered layouts. The first task defines the primary role of the -ForceGroup which gets generated from the preset. - -Example: - -.. code:: yaml - - name: SA-10/S-300PS # The name of the group - tasks: # Define at least 1 task - - LORAD # The task(s) the Group can fulfill - units: # Define at least 1 unit - - SAM SA-10 S-300 "Grumble" Clam Shell SR - - SAM SA-10 S-300 "Grumble" Big Bird SR - - SAM SA-10 S-300 "Grumble" C2 - - SAM SA-10 S-300 "Grumble" Flap Lid TR - - SAM SA-10 S-300 "Grumble" TEL D - - SAM SA-10 S-300 "Grumble" TEL C - statics: # Optional - - # Add some statics here - layouts: # Define at least one layout - - S-300 Site # prefered layouts for these groups - -Resources: - -* A list of all available preset groups can be found here: `resources/groups`_ -* All possible tasks can be found in the `game/data/groups.py`_ -* Units are defined with the variant name found in `resources/units`_ - -.. _game/data/groups.py: https://github.com/dcs-liberation/dcs_liberation/blob/develop/game/data/groups.py -.. _resources/units: https://github.com/dcs-liberation/dcs_liberation/tree/develop/resources/units \ No newline at end of file diff --git a/docs/modding/weather.rst b/docs/modding/weather.rst deleted file mode 100644 index cb11a1afc..000000000 --- a/docs/modding/weather.rst +++ /dev/null @@ -1,76 +0,0 @@ -####### -Weather -####### - -Weather conditions in DCS Liberation are randomly generated at the start of each -turn. Some of the inputs to that generator (more to come) can be controlled via -the config files in ``resources/weather``. - -********** -Archetypes -********** - -A weather archetype defines the the conditions for a style of weather, such as -"clear", or "raining". There are currently four archetypes: - -1. clear -2. cloudy -3. raining -4. thunderstorm - -The odds of each archetype appearing in each season are defined in the theater -yaml files (``resources/theaters/*/info.yaml``). - -.. literalinclude:: ../../resources/weather/archetypes/clear.yaml - :language: yaml - :linenos: - :caption: resources/weather/archetypes/clear.yaml - -Wind speeds -=========== - -DCS missions define wind with a speed and heading at each of three altitudes: - -1. MSL -2. 2000 meters -3. 8000 meters - -Blending between each altitude band is done in a manner defined by DCS. - -Liberation randomly generates a direction for the wind at MSL, and each other -altitude band will have wind within +/- 90 degrees of that heading. - -Wind speeds can be modded by altering the ``speed`` dict in the archetype yaml. -The only random distribution currently supported is the Weibull distribution, so -all archetypes currently use: - -.. code:: yaml - - speed: - weibull: - ... - -The Weibull distribution has two parameters: a shape and a scale. - -The scale is simplest to understand. 63.2% of all outcomes of the distribution -are below the scale parameter. - -The shape controls where the peak of the distribution is. See the examples in -the links below for illustrations and guidelines, but generally speaking low -values (between 1 and 2.6) will cause low speeds to be more common, medium -values (around 3) will be fairly evenly distributed around the median, and high -values (greater than 3.7) will cause high speeds to be more common. As wind -speeds tend to be higher at higher altitudes and fairly slow close to the -ground, you typically want a low value for MSL, a medium value for 2000m, and a -high value for 8000m. - -For examples, see https://statisticsbyjim.com/probability/weibull-distribution/. -To experiment with different inputs, use Wolfram Alpha, e.g. -https://www.wolframalpha.com/input?i=weibull+distribution+1.5+5. - -When generating wind speeds, each subsequent altitude band will have the lower -band's speed added to its scale parameter. That is, for the example above, the -actual scale parameter of ``at_2000m`` will be ``20 + wind speed at MSL``, and -the scale parameter of ``at_8000m`` will be ``20 + wind speed at 2000m``. This -is to ensure that a generally windy day (high wind speed at MSL) will create -similarly high winds at higher altitudes and vice versa. diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index a36b74ed3..000000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -myst-parser -sphinx_rtd_theme diff --git a/game/__init__.py b/game/__init__.py deleted file mode 100644 index 250f4a359..000000000 --- a/game/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .game import Game -from .version import VERSION diff --git a/game/aircraftparkinglocation.py b/game/aircraftparkinglocation.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/armedforces/armedforces.py b/game/armedforces/armedforces.py deleted file mode 100644 index b8d34a61b..000000000 --- a/game/armedforces/armedforces.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -import random -from typing import TYPE_CHECKING, Iterator, Optional -from game.data.groups import GroupTask -from game.armedforces.forcegroup import ForceGroup -from game.layout import LAYOUTS -from game.profiling import logged_duration - -if TYPE_CHECKING: - from game.factions.faction import Faction - - -class ArmedForces: - """Represents all ForceGroups which are available to the faction""" - - def __init__(self, faction: Faction): - self.forces: list[ForceGroup] = [] - with logged_duration(f"Loading armed forces for {faction.name}"): - self._load_forces(faction) - - def add_or_update_force_group(self, new_group: ForceGroup) -> None: - """Adds or update a forcegroup depending if a forcegroup with the exact same - tasking already exists""" - # Check if a force group with the same tasking already exists - for force_group in self.forces: - if force_group.tasks == new_group.tasks: - # Update existing group if tasks are equal - force_group.merge_group(new_group) - return - # Add a new force group - self.forces.append(new_group) - - def _load_forces(self, faction: Faction) -> None: - """Initialize the ArmedForces for the given faction. - This will create a ForceGroup for each generic Layout and PresetGroup""" - - # Generate ForceGroup for all generic layouts by iterating over - # all layouts which are usable by the given faction. - for layout in LAYOUTS.layouts: - if layout.generic and layout.usable_by_faction(faction): - # Creates a faction compatible GorceGroup - self.add_or_update_force_group(ForceGroup.for_layout(layout, faction)) - - # Add all preset groups afterwards to prevent them being merged with generics - for preset_group in faction.preset_groups: - self.forces.append(preset_group.initialize_for_faction(faction)) - - def groups_for_task(self, group_task: GroupTask) -> Iterator[ForceGroup]: - for force_group in self.forces: - if group_task in force_group.tasks: - yield force_group - - def groups_for_tasks(self, tasks: list[GroupTask]) -> list[ForceGroup]: - groups = [] - for task in tasks: - for group in self.groups_for_task(task): - if group not in groups: - groups.append(group) - return sorted(groups, key=lambda g: g.name) - - def random_group_for_task(self, group_task: GroupTask) -> Optional[ForceGroup]: - unit_groups = list(self.groups_for_task(group_task)) - return random.choice(unit_groups) if unit_groups else None diff --git a/game/armedforces/forcegroup.py b/game/armedforces/forcegroup.py deleted file mode 100644 index 4b0b205a8..000000000 --- a/game/armedforces/forcegroup.py +++ /dev/null @@ -1,358 +0,0 @@ -from __future__ import annotations - -import logging -import random -from dataclasses import dataclass, field -from pathlib import Path -from typing import Any, ClassVar, Iterator, Optional, TYPE_CHECKING, Type - -import yaml -from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType - -from game.data.groups import GroupTask -from game.dcs.groundunittype import GroundUnitType -from game.dcs.helpers import static_type_from_name -from game.dcs.shipunittype import ShipUnitType -from game.dcs.unittype import UnitType -from game.layout import LAYOUTS -from game.layout.layout import TgoLayout, TgoLayoutUnitGroup -from game.point_with_heading import PointWithHeading -from game.theater.theatergroundobject import ( - IadsGroundObject, - IadsBuildingGroundObject, - NavalGroundObject, -) -from game.theater.theatergroup import IadsGroundGroup, IadsRole, TheaterGroup -from game.utils import escape_string_for_lua - -if TYPE_CHECKING: - from game import Game - from game.factions.faction import Faction - from game.theater import TheaterGroundObject, ControlPoint, PresetLocation - - -@dataclass -class ForceGroup: - """A logical group of multiple units and layouts which have a specific tasking. - - ForceGroups will be generated during game and coalition initialization based on - generic layouts and preset forcegroups. - - Every ForceGroup must have at least one unit, one task and one layout. - - A preset ForceGroup can for example be a S-300 SAM Battery which used many - different unit types which all together handle a specific tasking (AirDefense) - For this example the ForceGroup would consist of SR, TR, LN and so on next to - statics. This group also has the Tasking LORAD and can have multiple (at least one) - layouts which will be used to generate the actual DCS Group from it. - """ - - name: str - units: list[UnitType[Any]] - statics: list[Type[DcsUnitType]] - tasks: list[GroupTask] = field(default_factory=list) - layouts: list[TgoLayout] = field(default_factory=list) - - _by_name: ClassVar[dict[str, ForceGroup]] = {} - _loaded: bool = False - - @staticmethod - def for_layout(layout: TgoLayout, faction: Faction) -> ForceGroup: - """Create a ForceGroup from the given TgoLayout which is usable by the faction - - This will iterate through all possible TgoLayoutGroups and check if the - unit_types are accessible by the faction. All accessible units will be added to - the force group - """ - units: set[UnitType[Any]] = set() - statics: set[Type[DcsUnitType]] = set() - for unit_group in layout.all_unit_groups: - if unit_group.optional and not unit_group.fill: - continue - for unit_type in unit_group.possible_types_for_faction(faction): - if issubclass(unit_type, VehicleType): - units.add(next(GroundUnitType.for_dcs_type(unit_type))) - elif issubclass(unit_type, ShipType): - units.add(next(ShipUnitType.for_dcs_type(unit_type))) - elif issubclass(unit_type, StaticType): - statics.add(unit_type) - - return ForceGroup( - ", ".join([t.description for t in layout.tasks]), - list(units), - list(statics), - layout.tasks, - [layout], - ) - - def __str__(self) -> str: - return self.name - - def has_unit_for_layout_group(self, unit_group: TgoLayoutUnitGroup) -> bool: - for unit in self.units: - if ( - unit.dcs_unit_type in unit_group.unit_types - or unit.unit_class in unit_group.unit_classes - ): - return True - return False - - def initialize_for_faction(self, faction: Faction) -> ForceGroup: - """Initialize a ForceGroup for the given Faction. - This adds accessible units to LayoutGroups with the fill property""" - for layout in self.layouts: - for unit_group in layout.all_unit_groups: - if unit_group.fill and not self.has_unit_for_layout_group(unit_group): - for unit_type in unit_group.possible_types_for_faction(faction): - if issubclass(unit_type, VehicleType): - self.units.append( - next(GroundUnitType.for_dcs_type(unit_type)) - ) - elif issubclass(unit_type, ShipType): - self.units.append( - next(ShipUnitType.for_dcs_type(unit_type)) - ) - elif issubclass(unit_type, StaticType): - self.statics.append(unit_type) - return self - - @classmethod - def from_preset_group(cls, name: str) -> ForceGroup: - if not cls._loaded: - cls._load_all() - preset_group = cls._by_name[name] - # Return a copy of the PresetGroup as new ForceGroup - return ForceGroup( - name=str(preset_group.name), - units=list(preset_group.units), - statics=list(preset_group.statics), - tasks=list(preset_group.tasks), - layouts=list(preset_group.layouts), - ) - - def has_access_to_dcs_type(self, type: Type[DcsUnitType]) -> bool: - return ( - any(unit.dcs_unit_type == type for unit in self.units) - or type in self.statics - ) - - def dcs_unit_types_for_group( - self, unit_group: TgoLayoutUnitGroup - ) -> list[Type[DcsUnitType]]: - """Return all available DCS Unit Types which can be used in the given - TgoLayoutGroup""" - unit_types = [ - t for t in unit_group.unit_types if self.has_access_to_dcs_type(t) - ] - - alternative_types = [] - for accessible_unit in self.units: - if accessible_unit.unit_class in unit_group.unit_classes: - unit_types.append(accessible_unit.dcs_unit_type) - if accessible_unit.unit_class in unit_group.fallback_classes: - alternative_types.append(accessible_unit.dcs_unit_type) - - return unit_types or alternative_types - - def unit_types_for_group( - self, unit_group: TgoLayoutUnitGroup - ) -> Iterator[UnitType[Any]]: - for dcs_type in self.dcs_unit_types_for_group(unit_group): - if issubclass(dcs_type, VehicleType): - yield next(GroundUnitType.for_dcs_type(dcs_type)) - elif issubclass(dcs_type, ShipType): - yield next(ShipUnitType.for_dcs_type(dcs_type)) - - def statics_for_group( - self, unit_group: TgoLayoutUnitGroup - ) -> Iterator[Type[DcsUnitType]]: - for dcs_type in self.dcs_unit_types_for_group(unit_group): - if issubclass(dcs_type, StaticType): - yield dcs_type - - def random_dcs_unit_type_for_group( - self, unit_group: TgoLayoutUnitGroup - ) -> Type[DcsUnitType]: - """Return random DCS Unit Type which can be used in the given TgoLayoutGroup""" - return random.choice(self.dcs_unit_types_for_group(unit_group)) - - def merge_group(self, new_group: ForceGroup) -> None: - """Merge the group with another similar group.""" - # Unified name for the resulting group - self.name = ", ".join([t.description for t in self.tasks]) - # merge units, statics and layouts - self.units = list(set(self.units + new_group.units)) - self.statics = list(set(self.statics + new_group.statics)) - self.layouts = list(set(self.layouts + new_group.layouts)) - - def generate( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - game: Game, - ) -> TheaterGroundObject: - """Create a random TheaterGroundObject from the available templates""" - layout = random.choice(self.layouts) - return self.create_ground_object_for_layout( - layout, name, location, control_point, game - ) - - def create_ground_object_for_layout( - self, - layout: TgoLayout, - name: str, - location: PresetLocation, - control_point: ControlPoint, - game: Game, - ) -> TheaterGroundObject: - """Create a TheaterGroundObject for the given template""" - go = layout.create_ground_object(name, location, control_point) - # Generate all groups using the randomization if it defined - for tgo_group in layout.groups: - for unit_group in tgo_group.unit_groups: - # Choose a random unit_type for the group - try: - unit_type = self.random_dcs_unit_type_for_group(unit_group) - except IndexError: - if unit_group.optional: - # If group is optional it is ok when no unit_type is available - continue - # if non-optional this is a error - raise RuntimeError( - f"No accessible unit for {self.name} - {unit_group.name}" - ) - tgo_group_name = f"{name} ({tgo_group.group_name})" - self.create_theater_group_for_tgo( - go, unit_group, tgo_group_name, game, unit_type - ) - - return go - - def create_theater_group_for_tgo( - self, - ground_object: TheaterGroundObject, - unit_group: TgoLayoutUnitGroup, - group_name: str, - game: Game, - unit_type: Type[DcsUnitType], - unit_count: Optional[int] = None, - ) -> None: - """Create a TheaterGroup and add it to the given TGO""" - # Random UnitCounter if not forced - if unit_count is None: - # Choose a random group_size based on the layouts unit_count - unit_count = unit_group.group_size - if unit_count == 0: - # No units to be created so dont create a theater group for them - return - # Generate Units - units = unit_group.generate_units(ground_object, unit_type, unit_count) - # Get or create the TheaterGroup - ground_group = ground_object.group_by_name(group_name) - if ground_group is not None: - # TheaterGroup with this name exists already. Extend it - ground_group.units.extend(units) - else: - # TheaterGroup with the name was not created yet - ground_group = TheaterGroup.from_template( - game.next_group_id(), group_name, units, ground_object - ) - # Special handling when part of the IADS (SAM, EWR, IADS Building, Navy) - if ( - isinstance(ground_object, IadsGroundObject) - or isinstance(ground_object, IadsBuildingGroundObject) - or isinstance(ground_object, NavalGroundObject) - ): - # Recreate the TheaterGroup as IadsGroundGroup - ground_group = IadsGroundGroup.from_group(ground_group) - if unit_group.sub_task is not None: - # Use the special sub_task of the TheaterGroup - iads_task = unit_group.sub_task - else: - # Use the primary task of the ForceGroup - iads_task = self.tasks[0] - # Set the iads_role according the the task for the group - ground_group.iads_role = IadsRole.for_task(iads_task) - - ground_object.groups.append(ground_group) - - # A layout has to be created with an orientation of 0 deg. - # Therefore the the clockwise rotation angle is always the heading of the - # groundobject without any calculation needed - rotation = ground_object.heading - - # Assign UniqueID, name and align relative to ground_object - for unit in units: - unit.id = game.next_unit_id() - # Add unit name escaped so that we do not have scripting issues later - unit.name = escape_string_for_lua( - unit.unit_type.variant_id if unit.unit_type else unit.type.name - ) - unit.position = PointWithHeading.from_point( - ground_object.position + unit.position, - # Align heading to GroundObject defined by the campaign designer - unit.position.heading + rotation, - ) - if ( - unit.unit_type is not None - and isinstance(unit.unit_type, GroundUnitType) - and unit.unit_type.reversed_heading - ): - # Reverse the heading of the unit - unit.position.heading = unit.position.heading.opposite - # Rotate unit around the center to align the orientation of the group - unit.position.rotate(ground_object.position, rotation) - - @classmethod - def _load_all(cls) -> None: - for file in Path("resources/groups").glob("*.yaml"): - if not file.is_file(): - raise RuntimeError(f"{file.name} is not a valid ForceGroup") - - with file.open(encoding="utf-8") as data_file: - data = yaml.safe_load(data_file) - - name = data["name"] - - group_tasks = [GroupTask.by_description(n) for n in data.get("tasks")] - if not group_tasks: - logging.error(f"ForceGroup {name} has no valid tasking") - continue - - units: list[UnitType[Any]] = [] - for unit in data.get("units"): - if GroundUnitType.exists(unit): - units.append(GroundUnitType.named(unit)) - elif ShipUnitType.exists(unit): - units.append(ShipUnitType.named(unit)) - else: - logging.error(f"Unit {unit} of ForceGroup {name} is invalid") - if len(units) == 0: - logging.error(f"ForceGroup {name} has no valid units") - continue - - statics = [] - for static in data.get("statics", []): - static_type = static_type_from_name(static) - if static_type is None: - logging.error(f"Static {static} for {file} is not valid") - else: - statics.append(static_type) - - layouts = [LAYOUTS.by_name(n) for n in data.get("layouts")] - if not layouts: - logging.error(f"ForceGroup {name} has no valid layouts") - continue - - force_group = ForceGroup( - name=name, - units=units, - statics=statics, - tasks=group_tasks, - layouts=layouts, - ) - - cls._by_name[force_group.name] = force_group - - cls._loaded = True diff --git a/game/atcdata.py b/game/atcdata.py deleted file mode 100644 index 674cae9b0..000000000 --- a/game/atcdata.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Optional - -from dcs.task import Modulation -from dcs.terrain import Airport - -from game.radio.radios import RadioFrequency - - -@dataclass -class AtcData: - hf: RadioFrequency - vhf_fm: RadioFrequency - vhf_am: RadioFrequency - uhf: RadioFrequency - - @classmethod - def from_pydcs(cls, airport: Airport) -> Optional[AtcData]: - if airport.atc_radio is None: - return None - return AtcData( - RadioFrequency(airport.atc_radio.hf_hz, Modulation.FM), - RadioFrequency(airport.atc_radio.vhf_low_hz, Modulation.FM), - RadioFrequency(airport.atc_radio.vhf_high_hz, Modulation.AM), - RadioFrequency(airport.atc_radio.uhf_hz, Modulation.AM), - ) diff --git a/game/ato/__init__.py b/game/ato/__init__.py deleted file mode 100644 index 7fac43a05..000000000 --- a/game/ato/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .flight import Flight -from .flighttype import FlightType -from .flightwaypoint import FlightWaypoint -from .package import Package diff --git a/game/ato/airtaaskingorder.py b/game/ato/airtaaskingorder.py deleted file mode 100644 index fca038351..000000000 --- a/game/ato/airtaaskingorder.py +++ /dev/null @@ -1,29 +0,0 @@ -from dataclasses import dataclass, field -from typing import List - -from game.ato.package import Package - - -@dataclass -class AirTaskingOrder: - """The entire ATO for one coalition.""" - - #: The set of all planned packages in the ATO. - packages: List[Package] = field(default_factory=list) - - def add_package(self, package: Package) -> None: - """Adds a package to the ATO.""" - self.packages.append(package) - - def remove_package(self, package: Package) -> None: - """Removes a package from the ATO.""" - # Remove all the flights individually so the database gets updated. - for flight in list(package.flights): - package.remove_flight(flight) - self.packages.remove(package) - - def clear(self) -> None: - """Removes all packages from the ATO.""" - # Remove all packages individually so the database gets updated. - for package in list(self.packages): - self.remove_package(package) diff --git a/game/ato/closestairfields.py b/game/ato/closestairfields.py deleted file mode 100644 index 4dd0032e9..000000000 --- a/game/ato/closestairfields.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Objective adjacency lists.""" -from __future__ import annotations - -from typing import Dict, Iterator, List, Optional, TYPE_CHECKING - -from game.utils import Distance - -if TYPE_CHECKING: - from game.theater import ConflictTheater, ControlPoint, MissionTarget - - -class ClosestAirfields: - """Precalculates which control points are closes to the given target.""" - - def __init__( - self, target: MissionTarget, all_control_points: List[ControlPoint] - ) -> None: - self.target = target - # This cache is configured once on load, so it's important that it is - # complete and deterministic to avoid different behaviors across loads. - # E.g. https://github.com/dcs-liberation/dcs_liberation/issues/819 - self.closest_airfields: List[ControlPoint] = sorted( - all_control_points, key=lambda c: self.target.distance_to(c) - ) - - @property - def operational_airfields(self) -> Iterator[ControlPoint]: - return (c for c in self.closest_airfields if c.runway_is_operational()) - - def _airfields_within( - self, distance: Distance, operational: bool - ) -> Iterator[ControlPoint]: - airfields = ( - self.operational_airfields if operational else self.closest_airfields - ) - for cp in airfields: - if cp.distance_to(self.target) < distance.meters: - yield cp - else: - break - - def operational_airfields_within( - self, distance: Distance - ) -> Iterator[ControlPoint]: - """Iterates over all airfields within the given range of the target. - - Note that this iterates over *all* airfields, not just friendly - airfields. - """ - return self._airfields_within(distance, operational=True) - - def all_airfields_within(self, distance: Distance) -> Iterator[ControlPoint]: - """Iterates over all airfields within the given range of the target. - - Note that this iterates over *all* airfields, not just friendly - airfields. - """ - return self._airfields_within(distance, operational=False) - - -class ObjectiveDistanceCache: - theater: Optional[ConflictTheater] = None - closest_airfields: Dict[str, ClosestAirfields] = {} - - @classmethod - def set_theater(cls, theater: ConflictTheater) -> None: - if cls.theater is not None: - cls.closest_airfields = {} - cls.theater = theater - - @classmethod - def get_closest_airfields(cls, location: MissionTarget) -> ClosestAirfields: - if cls.theater is None: - raise RuntimeError("Call ObjectiveDistanceCache.set_theater before using") - - if location.name not in cls.closest_airfields: - cls.closest_airfields[location.name] = ClosestAirfields( - location, cls.theater.controlpoints - ) - return cls.closest_airfields[location.name] diff --git a/game/ato/flight.py b/game/ato/flight.py deleted file mode 100644 index 86942f4bf..000000000 --- a/game/ato/flight.py +++ /dev/null @@ -1,277 +0,0 @@ -from __future__ import annotations - -import uuid -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import Any, List, Optional, TYPE_CHECKING - -from dcs import Point -from dcs.planes import C_101CC, C_101EB, Su_33 - -from .flightmembers import FlightMembers -from .flightroster import FlightRoster -from .flightstate import FlightState, Navigating, Uninitialized -from .flightstate.killed import Killed -from ..sidc import ( - Entity, - SidcDescribable, - StandardIdentity, - Status, - SymbolSet, -) - -if TYPE_CHECKING: - from game.dcs.aircrafttype import AircraftType - from game.sim.gameupdateevents import GameUpdateEvents - from game.sim.simulationresults import SimulationResults - from game.squadrons import Squadron, Pilot - from game.theater import ControlPoint - from game.transfers import TransferOrder - from game.data.weapons import WeaponType - from .flightmember import FlightMember - from .flightplans.flightplan import FlightPlan - from .flighttype import FlightType - from .flightwaypoint import FlightWaypoint - from .package import Package - from .starttype import StartType - - -class Flight(SidcDescribable): - def __init__( - self, - package: Package, - country: str, - squadron: Squadron, - count: int, - flight_type: FlightType, - start_type: StartType, - divert: Optional[ControlPoint], - custom_name: Optional[str] = None, - cargo: Optional[TransferOrder] = None, - roster: Optional[FlightRoster] = None, - ) -> None: - self.id = uuid.uuid4() - self.package = package - self.country = country - self.coalition = squadron.coalition - self.squadron = squadron - self.flight_type = flight_type - self.squadron.claim_inventory(count) - if roster is None: - self.roster = FlightMembers(self, initial_size=count) - else: - self.roster = FlightMembers.from_roster(self, roster) - self.divert = divert - self.start_type = start_type - self.custom_name = custom_name - self.use_same_loadout_for_all_members = True - - # Only used by transport missions. - self.cargo = cargo - - # Flight properties that can be set in the mission editor. This is used for - # things like HMD selection, ripple quantity, etc. Any values set here will take - # the place of the defaults defined by DCS. - # - # This is a part of the Flight rather than the Loadout because DCS does not - # associate these choices with the loadout, and we don't want to reset these - # options when players switch loadouts. - self.props: dict[str, Any] = {} - - # Used for simulating the travel to first contact. - self.state: FlightState = Uninitialized(self, squadron.settings) - - # Will be replaced with a more appropriate FlightPlan later, but start with a - # cheaply constructed one since adding more flights to the package may affect - # the optimal layout. - from .flightplans.flightplanbuildertypes import FlightPlanBuilderTypes - - self._flight_plan_builder = FlightPlanBuilderTypes.for_flight(self)(self) - - @property - def flight_plan(self) -> FlightPlan[Any]: - return self._flight_plan_builder.get_or_build() - - def degrade_to_custom_flight_plan(self) -> None: - from .flightplans.custom import Builder as CustomBuilder - - self._flight_plan_builder = CustomBuilder(self, self.flight_plan.waypoints[1:]) - self.recreate_flight_plan() - # We need to clear the existing actions/options when moving the waypoints into - # the new flight plan because the actions/options that are currently set will be - # the actions of whatever flight plan was previously used. - # https://github.com/dcs-liberation/dcs_liberation/issues/3189 - for waypoint in self.flight_plan.iter_waypoints(): - waypoint.actions.clear() - waypoint.options.clear() - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__.copy() - # Avoid persisting the flight state since that's not (currently) used outside - # mission generation. This is a bit of a hack for the moment and in the future - # we will need to persist the flight state, but for now keep it out of save - # compat (it also contains a generator that cannot be pickled). - del state["state"] - return state - - def __setstate__(self, state: dict[str, Any]) -> None: - state["state"] = Uninitialized(self, state["squadron"].settings) - self.__dict__.update(state) - - @property - def blue(self) -> bool: - return self.squadron.player - - @property - def standard_identity(self) -> StandardIdentity: - return StandardIdentity.FRIEND if self.blue else StandardIdentity.HOSTILE_FAKER - - @property - def sidc_status(self) -> Status: - return Status.PRESENT if self.alive else Status.PRESENT_DESTROYED - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.AIR, self.flight_type.entity_type - - @property - def departure(self) -> ControlPoint: - return self.squadron.location - - @property - def arrival(self) -> ControlPoint: - return self.squadron.arrival - - @property - def count(self) -> int: - return self.roster.max_size - - @property - def client_count(self) -> int: - return self.roster.player_count - - @property - def unit_type(self) -> AircraftType: - return self.squadron.aircraft - - @property - def is_helo(self) -> bool: - return self.unit_type.dcs_unit_type.helicopter - - @property - def points(self) -> List[FlightWaypoint]: - return self.flight_plan.waypoints[1:] - - def position(self) -> Point: - return self.state.estimate_position() - - def resize(self, new_size: int) -> None: - self.squadron.claim_inventory(new_size - self.count) - self.roster.resize(new_size) - - def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None: - self.roster.set_pilot(index, pilot) - - @property - def missing_pilots(self) -> int: - return self.roster.missing_pilots - - def iter_members(self) -> Iterator[FlightMember]: - yield from self.roster.members - - def set_flight_type(self, var: FlightType) -> None: - self.flight_type = var - - # Update _flight_plan_builder so that the builder class remains relevant - # to the flight type - from .flightplans.flightplanbuildertypes import FlightPlanBuilderTypes - - self._flight_plan_builder = FlightPlanBuilderTypes.for_flight(self)(self) - - def return_pilots_and_aircraft(self) -> None: - self.roster.clear() - self.squadron.claim_inventory(-self.count) - - def max_takeoff_fuel(self) -> Optional[float]: - # Special case so Su 33 and C101 can take off - unit_type = self.unit_type.dcs_unit_type - if unit_type == Su_33: - if self.flight_type.is_air_to_air: - return Su_33.fuel_max / 2.2 - else: - return Su_33.fuel_max * 0.8 - elif unit_type in {C_101EB, C_101CC}: - return unit_type.fuel_max * 0.5 - return None - - def any_member_has_weapon_of_type(self, weapon_type: WeaponType) -> bool: - return any( - m.loadout.has_weapon_of_type(weapon_type) for m in self.iter_members() - ) - - def __repr__(self) -> str: - if self.custom_name: - return f"{self.custom_name} {self.count} x {self.unit_type}" - return f"[{self.flight_type}] {self.count} x {self.unit_type}" - - def __str__(self) -> str: - if self.custom_name: - return f"{self.custom_name} {self.count} x {self.unit_type}" - return f"[{self.flight_type}] {self.count} x {self.unit_type}" - - def abort(self) -> None: - from .flightplans.rtb import RtbFlightPlan - - self._flight_plan_builder = RtbFlightPlan.builder_type()(self) - plan = self._flight_plan_builder.get_or_build() - - self.set_state( - Navigating( - self, - self.squadron.settings, - plan.abort_index, - has_aborted=True, - ) - ) - - def set_state(self, state: FlightState) -> None: - self.state = state - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - self.state.on_game_tick(events, time, duration) - - def should_halt_sim(self) -> bool: - return self.state.should_halt_sim() - - @property - def alive(self) -> bool: - return self.state.alive - - def kill(self, results: SimulationResults, events: GameUpdateEvents) -> None: - # This is a bit messy while we're in transition from turn-based to turnless - # because we want the simulation to have minimal impact on the save game while - # turns exist so that loading a game is essentially a way to reset the - # simulation to the start of the turn. As such, we don't actually want to mark - # pilots killed or reduce squadron aircraft availability, but we do still need - # the UI to reflect that aircraft were lost and avoid generating those flights - # when the mission is generated. - # - # For now we do this by logging the kill in the SimulationResults, which is - # similar to the Debriefing. We also set the flight's state to Killed, which - # will prevent it from being spawned in the mission and updates the SIDC. - # This does leave an opportunity for players to cheat since the UI won't stop - # them from cancelling a dead flight, returning the aircraft to the pool. Not a - # big deal for now. - # TODO: Support partial kills. - self.set_state( - Killed(self.state.estimate_position(), self, self.squadron.settings) - ) - events.update_flight(self) - for pilot in self.roster.iter_pilots(): - if pilot is not None: - results.kill_pilot(self, pilot) - - def recreate_flight_plan(self, dump_debug_info: bool = False) -> None: - self._flight_plan_builder.regenerate(dump_debug_info) diff --git a/game/ato/flightmember.py b/game/ato/flightmember.py deleted file mode 100644 index a20859495..000000000 --- a/game/ato/flightmember.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from game.ato.loadouts import Loadout -from game.lasercodes import LaserCode - -if TYPE_CHECKING: - from game.squadrons import Pilot - - -class FlightMember: - def __init__(self, pilot: Pilot | None, loadout: Loadout) -> None: - self.pilot = pilot - self.loadout = loadout - self.use_custom_loadout = False - self.tgp_laser_code: LaserCode | None = None - self.weapon_laser_code: LaserCode | None = None - self.properties: dict[str, bool | float | int] = {} - - def assign_tgp_laser_code(self, code: LaserCode) -> None: - if self.tgp_laser_code is not None: - raise RuntimeError( - f"{self.pilot} already has already been assigned laser code " - f"{self.tgp_laser_code}" - ) - self.tgp_laser_code = code - - def release_tgp_laser_code(self) -> None: - if self.tgp_laser_code is None: - raise RuntimeError(f"{self.pilot} has no assigned laser code") - - if self.weapon_laser_code == self.tgp_laser_code: - self.weapon_laser_code = None - self.tgp_laser_code.release() - self.tgp_laser_code = None - - @property - def is_player(self) -> bool: - if self.pilot is None: - return False - return self.pilot.player diff --git a/game/ato/flightmembers.py b/game/ato/flightmembers.py deleted file mode 100644 index 8baaf01b2..000000000 --- a/game/ato/flightmembers.py +++ /dev/null @@ -1,91 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from typing import Optional, TYPE_CHECKING - -from .flightmember import FlightMember -from .flightroster import FlightRoster -from .iflightroster import IFlightRoster -from .loadouts import Loadout - -if TYPE_CHECKING: - from game.squadrons import Pilot - from .flight import Flight - - -class FlightMembers(IFlightRoster): - def __init__(self, flight: Flight, initial_size: int = 0) -> None: - self.flight = flight - self.members: list[FlightMember] = [] - self.resize(initial_size) - - @staticmethod - def from_roster(flight: Flight, roster: FlightRoster) -> FlightMembers: - members = FlightMembers(flight) - loadout = Loadout.default_for(flight) - members.members = [FlightMember(p, loadout) for p in roster.pilots] - return members - - def iter_pilots(self) -> Iterator[Pilot | None]: - yield from (m.pilot for m in self.members) - - def pilot_at(self, idx: int) -> Pilot | None: - return self.members[idx].pilot - - @property - def max_size(self) -> int: - return len(self.members) - - @property - def player_count(self) -> int: - return len([m for m in self.members if m.is_player]) - - @property - def missing_pilots(self) -> int: - return len([m for m in self.members if m.pilot is None]) - - def resize(self, new_size: int) -> None: - if self.max_size > new_size: - for member in self.members[new_size:]: - if (pilot := member.pilot) is not None: - self.flight.squadron.return_pilot(pilot) - if (code := member.tgp_laser_code) is not None: - code.release() - self.members = self.members[:new_size] - return - if self.max_size: - loadout = self.members[0].loadout.clone() - else: - loadout = Loadout.default_for(self.flight) - for _ in range(new_size - self.max_size): - member = FlightMember(self.flight.squadron.claim_available_pilot(), loadout) - member.use_custom_loadout = loadout.is_custom - self.members.append(member) - - def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None: - if pilot is not None: - self.flight.squadron.claim_pilot(pilot) - if (current_pilot := self.pilot_at(index)) is not None: - self.flight.squadron.return_pilot(current_pilot) - self.members[index].pilot = pilot - - def clear(self) -> None: - self.flight.squadron.return_pilots( - [p for p in self.iter_pilots() if p is not None] - ) - for member in self.members: - if (code := member.tgp_laser_code) is not None: - code.release() - - def use_same_loadout_for_all_members(self) -> None: - if not self.members: - return - loadout = self.members[0].loadout - for member in self.members[1:]: - # Do not clone the loadout, we want any changes in the UI to be mirrored - # across all flight members. - member.loadout = loadout - - def use_distinct_loadouts_for_each_member(self) -> None: - for member in self.members: - member.loadout = member.loadout.clone() diff --git a/game/ato/flightplans/__init__.py b/game/ato/flightplans/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/ato/flightplans/aewc.py b/game/ato/flightplans/aewc.py deleted file mode 100644 index 7534ce325..000000000 --- a/game/ato/flightplans/aewc.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -from datetime import timedelta -from typing import Type - -from game.ato.flightplans.ibuilder import IBuilder -from game.ato.flightplans.patrolling import PatrollingFlightPlan, PatrollingLayout -from game.ato.flightplans.waypointbuilder import WaypointBuilder -from game.utils import Distance, Heading, Speed, feet, knots, meters, nautical_miles - - -class AewcFlightPlan(PatrollingFlightPlan[PatrollingLayout]): - @property - def patrol_duration(self) -> timedelta: - return timedelta(hours=4) - - @property - def patrol_speed(self) -> Speed: - altitude = self.layout.patrol_start.alt - if self.flight.unit_type.preferred_patrol_speed(altitude) is not None: - return self.flight.unit_type.preferred_patrol_speed(altitude) - return knots(390) - - @property - def engagement_distance(self) -> Distance: - # TODO: Factor out a common base of the combat and non-combat race-tracks. - # No harm in setting this, but we ought to clean up a bit. - return meters(0) - - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]): - def layout(self) -> PatrollingLayout: - racetrack_half_distance = nautical_miles(30).meters - - location = self.package.target - - closest_boundary = self.threat_zones.closest_boundary(location.position) - heading_to_threat_boundary = Heading.from_degrees( - location.position.heading_between_point(closest_boundary) - ) - distance_to_threat = meters( - location.position.distance_to_point(closest_boundary) - ) - orbit_heading = heading_to_threat_boundary - - # Station 80nm outside the threat zone. - threat_buffer = nautical_miles(80) - if self.threat_zones.threatened(location.position): - orbit_distance = distance_to_threat + threat_buffer - else: - orbit_distance = distance_to_threat - threat_buffer - - racetrack_center = location.position.point_from_heading( - orbit_heading.degrees, orbit_distance.meters - ) - - racetrack_start = racetrack_center.point_from_heading( - orbit_heading.right.degrees, racetrack_half_distance - ) - - racetrack_end = racetrack_center.point_from_heading( - orbit_heading.left.degrees, racetrack_half_distance - ) - - builder = WaypointBuilder(self.flight, self.coalition) - - if self.flight.unit_type.patrol_altitude is not None: - altitude = self.flight.unit_type.patrol_altitude - else: - altitude = feet(25000) - - racetrack = builder.race_track(racetrack_start, racetrack_end, altitude) - - return PatrollingLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, racetrack_start, altitude - ), - nav_from=builder.nav_path( - racetrack_end, self.flight.arrival.position, altitude - ), - patrol_start=racetrack[0], - patrol_end=racetrack[1], - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> AewcFlightPlan: - return AewcFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/airassault.py b/game/ato/flightplans/airassault.py deleted file mode 100644 index e74b41026..000000000 --- a/game/ato/flightplans/airassault.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from datetime import datetime -from typing import Iterator, TYPE_CHECKING, Type - -from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout -from game.theater.controlpoint import ControlPointType -from game.theater.missiontarget import MissionTarget -from game.utils import Distance, feet, meters -from .ibuilder import IBuilder -from .planningerror import PlanningError -from .uizonedisplay import UiZone, UiZoneDisplay -from .waypointbuilder import WaypointBuilder -from ..flightwaypoint import FlightWaypointType - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class AirAssaultLayout(StandardLayout): - # The pickup point is optional because we don't always need to load the cargo. When - # departing from a carrier, LHA, or off-map spawn, the cargo is pre-loaded. - pickup: FlightWaypoint | None - nav_to_ingress: list[FlightWaypoint] - ingress: FlightWaypoint - drop_off: FlightWaypoint - # This is an implementation detail used by CTLD. The aircraft will not go to this - # waypoint. It is used by CTLD as the destination for unloaded troops. - target: FlightWaypoint - nav_to_home: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - if self.pickup is not None: - yield self.pickup - yield from self.nav_to_ingress - yield self.ingress - yield self.drop_off - yield self.target - yield from self.nav_to_home - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class AirAssaultFlightPlan(StandardFlightPlan[AirAssaultLayout], UiZoneDisplay): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.drop_off - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.tot_waypoint: - return self.tot - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - @property - def ctld_target_zone_radius(self) -> Distance: - return meters(2500) - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.package.time_over_target - - def ui_zone(self) -> UiZone: - return UiZone( - [self.layout.target.position], - self.ctld_target_zone_radius, - ) - - -class Builder(IBuilder[AirAssaultFlightPlan, AirAssaultLayout]): - def layout(self) -> AirAssaultLayout: - if not self.flight.is_helo: - raise PlanningError("Air assault is only usable by helicopters") - assert self.package.waypoints is not None - - altitude = self.doctrine.helicopter.air_assault_nav_altitude - altitude_is_agl = self.flight.is_helo - - builder = WaypointBuilder(self.flight, self.coalition) - - if self.flight.departure.cptype in [ - ControlPointType.AIRCRAFT_CARRIER_GROUP, - ControlPointType.LHA_GROUP, - ControlPointType.OFF_MAP, - ]: - # Off_Map spawns will be preloaded - # Carrier operations load the logistics directly from the carrier - pickup = None - pickup_position = self.flight.departure.position - else: - # TODO The calculation of the Pickup LZ is currently randomized. This - # leads to the problem that we can not gurantee that the LZ is clear of - # obstacles. This has to be improved in the future so that the Mission can - # be autoplanned. In the current state the User has to check the created - # Waypoints for the Pickup and Dropoff LZs are free of obstacles. - # Create a special pickup zone for Helos from Airbase / FOB - pickup = builder.pickup_zone( - MissionTarget( - "Pickup Zone", - self.flight.departure.position.random_point_within(1200, 600), - ) - ) - pickup_position = pickup.position - assault_area = builder.assault_area(self.package.target) - heading = self.package.target.position.heading_between_point(pickup_position) - - # TODO we can not gurantee a safe LZ for DropOff. See comment above. - drop_off_zone = MissionTarget( - "Dropoff zone", - self.package.target.position.point_from_heading(heading, 1200), - ) - - return AirAssaultLayout( - departure=builder.takeoff(self.flight.departure), - pickup=pickup, - nav_to_ingress=builder.nav_path( - pickup_position, - self.package.waypoints.ingress, - altitude, - altitude_is_agl, - ), - ingress=builder.ingress( - FlightWaypointType.INGRESS_AIR_ASSAULT, - self.package.waypoints.ingress, - self.package.target, - ), - drop_off=builder.dropoff_zone(drop_off_zone), - target=assault_area, - nav_to_home=builder.nav_path( - drop_off_zone.position, - self.flight.arrival.position, - altitude, - altitude_is_agl, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> AirAssaultFlightPlan: - return AirAssaultFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/airlift.py b/game/ato/flightplans/airlift.py deleted file mode 100644 index d62c4e7aa..000000000 --- a/game/ato/flightplans/airlift.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime -from typing import TYPE_CHECKING, Type - -from game.theater.missiontarget import MissionTarget -from game.utils import feet -from .ibuilder import IBuilder -from .planningerror import PlanningError -from .standard import StandardFlightPlan, StandardLayout -from .waypointbuilder import WaypointBuilder - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class AirliftLayout(StandardLayout): - nav_to_pickup: list[FlightWaypoint] - # There will not be a pickup waypoint when the pickup airfield is the departure - # airfield for cargo planes, as the cargo is pre-loaded. Helicopters will still pick - # up the cargo near the airfield. - pickup: FlightWaypoint | None - # pickup_zone will be used for player flights to create the CTLD stuff - ctld_pickup_zone: FlightWaypoint | None - nav_to_drop_off: list[FlightWaypoint] - # There will not be a drop-off waypoint when the drop-off airfield and the arrival - # airfield is the same for a cargo plane, as planes will land to unload and we don't - # want a double landing. Helicopters will still drop their cargo near the airfield - # before landing. - drop_off: FlightWaypoint | None - # drop_off_zone will be used for player flights to create the CTLD stuff - ctld_drop_off_zone: FlightWaypoint | None - nav_to_home: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to_pickup - if self.pickup is not None: - yield self.pickup - if self.ctld_pickup_zone is not None: - yield self.ctld_pickup_zone - yield from self.nav_to_drop_off - if self.drop_off is not None: - yield self.drop_off - if self.ctld_drop_off_zone is not None: - yield self.ctld_drop_off_zone - yield from self.nav_to_home - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class AirliftFlightPlan(StandardFlightPlan[AirliftLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def tot_waypoint(self) -> FlightWaypoint: - # The TOT is the time that the cargo will be dropped off. If the drop-off - # location is the arrival airfield and this is not a helicopter flight, there - # will not be a separate drop-off waypoint; the arrival landing waypoint is the - # drop-off waypoint. - return self.layout.drop_off or self.layout.arrival - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - # TOT planning isn't really useful for transports. They're behind the front - # lines so no need to wait for escorts or for other missions to complete. - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.package.time_over_target - - -class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]): - def layout(self) -> AirliftLayout: - cargo = self.flight.cargo - if cargo is None: - raise PlanningError( - "Cannot plan transport mission for flight with no cargo." - ) - - altitude = feet(1500) - altitude_is_agl = True - - builder = WaypointBuilder(self.flight, self.coalition) - - pickup = None - drop_off = None - pickup_zone = None - drop_off_zone = None - - if cargo.origin != self.flight.departure: - pickup = builder.cargo_stop(cargo.origin) - if cargo.next_stop != self.flight.arrival: - drop_off = builder.cargo_stop(cargo.next_stop) - - if self.flight.is_helo: - # Create CTLD Zones for Helo flights - pickup_zone = builder.pickup_zone( - MissionTarget( - "Pickup Zone", cargo.origin.position.random_point_within(1000, 200) - ) - ) - drop_off_zone = builder.dropoff_zone( - MissionTarget( - "Dropoff zone", - cargo.next_stop.position.random_point_within(1000, 200), - ) - ) - # Show the zone waypoints only to the player - pickup_zone.only_for_player = True - drop_off_zone.only_for_player = True - - nav_to_pickup = builder.nav_path( - self.flight.departure.position, - cargo.origin.position, - altitude, - altitude_is_agl, - ) - - return AirliftLayout( - departure=builder.takeoff(self.flight.departure), - nav_to_pickup=nav_to_pickup, - pickup=pickup, - ctld_pickup_zone=pickup_zone, - nav_to_drop_off=builder.nav_path( - cargo.origin.position, - cargo.next_stop.position, - altitude, - altitude_is_agl, - ), - drop_off=drop_off, - ctld_drop_off_zone=drop_off_zone, - nav_to_home=builder.nav_path( - cargo.origin.position, - self.flight.arrival.position, - altitude, - altitude_is_agl, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> AirliftFlightPlan: - return AirliftFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/antiship.py b/game/ato/flightplans/antiship.py deleted file mode 100644 index b883fd9fa..000000000 --- a/game/ato/flightplans/antiship.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -from typing import Type - -from game.theater import NavalControlPoint -from game.theater.theatergroundobject import NavalGroundObject -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from .waypointbuilder import StrikeTarget -from ..flightwaypointtype import FlightWaypointType - - -class AntiShipFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[AntiShipFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - from game.transfers import CargoShip - - if isinstance(location, NavalControlPoint): - targets = self.anti_ship_targets_for_tgo(location.find_main_tgo()) - elif isinstance(location, NavalGroundObject): - targets = self.anti_ship_targets_for_tgo(location) - elif isinstance(location, CargoShip): - targets = [StrikeTarget(location.name, location)] - else: - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - return self._build(FlightWaypointType.INGRESS_ANTI_SHIP, targets) - - @staticmethod - def anti_ship_targets_for_tgo(tgo: NavalGroundObject) -> list[StrikeTarget]: - return [StrikeTarget(f"{g.group_name} at {tgo.name}", g) for g in tgo.groups] - - def build(self, dump_debug_info: bool = False) -> AntiShipFlightPlan: - return AntiShipFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/bai.py b/game/ato/flightplans/bai.py deleted file mode 100644 index 22b8f9158..000000000 --- a/game/ato/flightplans/bai.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -from typing import Type - -from game.theater.theatergroundobject import TheaterGroundObject -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from .waypointbuilder import StrikeTarget -from ..flightwaypointtype import FlightWaypointType - - -class BaiFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[BaiFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - from game.transfers import Convoy - - targets: list[StrikeTarget] = [] - if isinstance(location, TheaterGroundObject): - for group in location.groups: - if group.units: - targets.append( - StrikeTarget(f"{group.group_name} at {location.name}", group) - ) - elif isinstance(location, Convoy): - targets.append(StrikeTarget(location.name, location)) - else: - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - return self._build(FlightWaypointType.INGRESS_BAI, targets) - - def build(self, dump_debug_info: bool = False) -> BaiFlightPlan: - return BaiFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/barcap.py b/game/ato/flightplans/barcap.py deleted file mode 100644 index 401a6e8b9..000000000 --- a/game/ato/flightplans/barcap.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - -import random -from datetime import timedelta -from typing import Type - -from game.theater import FrontLine -from game.utils import Distance, Speed, feet -from .capbuilder import CapBuilder -from .invalidobjectivelocation import InvalidObjectiveLocation -from .patrolling import PatrollingFlightPlan, PatrollingLayout -from .waypointbuilder import WaypointBuilder - - -class BarCapFlightPlan(PatrollingFlightPlan[PatrollingLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def patrol_duration(self) -> timedelta: - return self.flight.coalition.doctrine.cap.duration - - @property - def patrol_speed(self) -> Speed: - return self.flight.unit_type.preferred_patrol_speed( - self.layout.patrol_start.alt - ) - - @property - def engagement_distance(self) -> Distance: - return self.flight.coalition.doctrine.cap.engagement_range - - -class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]): - def layout(self) -> PatrollingLayout: - location = self.package.target - - if isinstance(location, FrontLine): - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - start_pos, end_pos = self.cap_racetrack_for_objective(location, barcap=True) - - preferred_alt = self.flight.unit_type.preferred_patrol_altitude - randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000) - patrol_alt = max( - self.doctrine.cap.min_patrol_altitude, - min(self.doctrine.cap.max_patrol_altitude, randomized_alt), - ) - - builder = WaypointBuilder(self.flight, self.coalition) - start, end = builder.race_track(start_pos, end_pos, patrol_alt) - - return PatrollingLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, start.position, patrol_alt - ), - nav_from=builder.nav_path( - end.position, self.flight.arrival.position, patrol_alt - ), - patrol_start=start, - patrol_end=end, - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> BarCapFlightPlan: - return BarCapFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/capbuilder.py b/game/ato/flightplans/capbuilder.py deleted file mode 100644 index 40fce198e..000000000 --- a/game/ato/flightplans/capbuilder.py +++ /dev/null @@ -1,132 +0,0 @@ -from __future__ import annotations - -import copy -import random -from abc import ABC -from typing import Any, TYPE_CHECKING, TypeVar - -from dcs import Point -from shapely.geometry import Point as ShapelyPoint - -from game.utils import Heading, meters, nautical_miles -from .flightplan import FlightPlan -from .patrolling import PatrollingLayout -from ..closestairfields import ObjectiveDistanceCache -from ..flightplans.ibuilder import IBuilder -from ..flightplans.planningerror import PlanningError - -if TYPE_CHECKING: - from game.theater import MissionTarget - -FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[Any]) -LayoutT = TypeVar("LayoutT", bound=PatrollingLayout) - - -class CapBuilder(IBuilder[FlightPlanT, LayoutT], ABC): - def cap_racetrack_for_objective( - self, location: MissionTarget, barcap: bool - ) -> tuple[Point, Point]: - closest_cache = ObjectiveDistanceCache.get_closest_airfields(location) - closest_friendly_field = ( - None # keep track of closest frieldly airfield in case we need it - ) - for airfield in closest_cache.operational_airfields: - # If the mission is a BARCAP of an enemy airfield, find the *next* - # closest enemy airfield. - if airfield == self.package.target: - continue - if airfield.captured != self.is_player: - closest_airfield = airfield - break - elif closest_friendly_field is None: - closest_friendly_field = airfield - else: - if barcap: - # If planning a BARCAP, we should be able to find at least one enemy - # airfield. If we can't, it's an error. - raise PlanningError("Could not find any enemy airfields") - else: - # if we cannot find any friendly or enemy airfields other than the target, - # there's nothing we can do - if closest_friendly_field is None: - raise PlanningError( - "Could not find any enemy or friendly airfields" - ) - - # If planning other race tracks (TARCAPs, currently), the target may be - # the only enemy airfield. In this case, set the race track orientation using - # a virtual point equi-distant from but opposite to the target from the closest - # friendly airfield like below, where F is the closest friendly airfield, T is - # the sole enemy airfield and V the virtual point - # - # F ---- T ----- V - # - # We need to create this virtual point, rather than using F to make sure - # the race track is aligned towards the target. - closest_friendly_field_position = copy.deepcopy( - closest_friendly_field.position - ) - closest_airfield = closest_friendly_field - closest_airfield.position.x = ( - 2 * self.package.target.position.x - - closest_friendly_field_position.x - ) - closest_airfield.position.y = ( - 2 * self.package.target.position.y - - closest_friendly_field_position.y - ) - - heading = Heading.from_degrees( - location.position.heading_between_point(closest_airfield.position) - ) - - position = ShapelyPoint( - self.package.target.position.x, self.package.target.position.y - ) - - if barcap: - # BARCAPs should remain far enough back from the enemy that their - # commit range does not enter the enemy's threat zone. Include a 5nm - # buffer. - distance_to_no_fly = ( - meters(position.distance(self.threat_zones.all)) - - self.doctrine.cap.engagement_range - - nautical_miles(5) - ) - max_track_length = self.doctrine.cap.max_track_length - else: - # Other race tracks (TARCAPs, currently) just try to keep some - # distance from the nearest enemy airbase, but since they are by - # definition in enemy territory they can't avoid the threat zone - # without being useless. - min_distance_from_enemy = nautical_miles(20) - distance_to_airfield = meters( - closest_airfield.position.distance_to_point( - self.package.target.position - ) - ) - distance_to_no_fly = distance_to_airfield - min_distance_from_enemy - - # TARCAPs fly short racetracks because they need to react faster. - max_track_length = self.doctrine.cap.min_track_length + 0.3 * ( - self.doctrine.cap.max_track_length - self.doctrine.cap.min_track_length - ) - - min_cap_distance = min( - self.doctrine.cap.min_distance_from_cp, distance_to_no_fly - ) - max_cap_distance = min( - self.doctrine.cap.max_distance_from_cp, distance_to_no_fly - ) - - end = location.position.point_from_heading( - heading.degrees, - random.randint(int(min_cap_distance.meters), int(max_cap_distance.meters)), - ) - - track_length = random.randint( - int(self.doctrine.cap.min_track_length.meters), - int(max_track_length.meters), - ) - start = end.point_from_heading(heading.opposite.degrees, track_length) - return start, end diff --git a/game/ato/flightplans/cas.py b/game/ato/flightplans/cas.py deleted file mode 100644 index b27d762b0..000000000 --- a/game/ato/flightplans/cas.py +++ /dev/null @@ -1,163 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import timedelta -from typing import TYPE_CHECKING, Type - -from game.theater import FrontLine -from game.utils import Distance, Speed, kph, meters, dcs_to_shapely_point -from .ibuilder import IBuilder -from .invalidobjectivelocation import InvalidObjectiveLocation -from .patrolling import PatrollingFlightPlan, PatrollingLayout -from .uizonedisplay import UiZone, UiZoneDisplay -from .waypointbuilder import WaypointBuilder -from ..flightwaypointtype import FlightWaypointType -from ...flightplan.ipsolver import IpSolver -from ...persistence.paths import waypoint_debug_directory - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class CasLayout(PatrollingLayout): - ingress: FlightWaypoint - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to - yield self.ingress - yield self.patrol_start - yield self.patrol_end - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def patrol_duration(self) -> timedelta: - return self.flight.coalition.doctrine.cas.duration - - @property - def patrol_speed(self) -> Speed: - # 2021-08-02: patrol_speed will currently have no effect because - # CAS doesn't use OrbitAction. But all PatrollingFlightPlan are expected - # to have patrol_speed - return kph(0) - - @property - def engagement_distance(self) -> Distance: - from game.missiongenerator.frontlineconflictdescription import FRONTLINE_LENGTH - - return meters(FRONTLINE_LENGTH) / 2 - - @property - def combat_speed_waypoints(self) -> set[FlightWaypoint]: - return {self.layout.ingress, self.layout.patrol_start, self.layout.patrol_end} - - def ui_zone(self) -> UiZone: - midpoint = ( - self.layout.patrol_start.position + self.layout.patrol_end.position - ) / 2 - return UiZone( - [midpoint], - self.engagement_distance, - ) - - -class Builder(IBuilder[CasFlightPlan, CasLayout]): - def layout(self, dump_debug_info: bool) -> CasLayout: - location = self.package.target - - if not isinstance(location, FrontLine): - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, - ) - - bounds = FrontLineConflictDescription.frontline_bounds(location, self.theater) - patrol_start = bounds.left_position - patrol_end = bounds.right_position - - start_distance = patrol_start.distance_to_point(self.flight.departure.position) - end_distance = patrol_end.distance_to_point(self.flight.departure.position) - if end_distance < start_distance: - patrol_start, patrol_end = patrol_end, patrol_start - - builder = WaypointBuilder(self.flight, self.coalition) - - is_helo = self.flight.unit_type.dcs_unit_type.helicopter - patrol_altitude = self.doctrine.resolve_combat_altitude(is_helo) - use_agl_patrol_altitude = is_helo - - ip_solver = IpSolver( - dcs_to_shapely_point(self.flight.departure.position), - dcs_to_shapely_point(patrol_start), - self.doctrine, - self.threat_zones.all, - ) - ip_solver.set_debug_properties( - waypoint_debug_directory() / "IP", self.theater.terrain - ) - ingress_point_shapely = ip_solver.solve() - if dump_debug_info: - ip_solver.dump_debug_info() - - ingress_point = patrol_start.new_in_same_map( - ingress_point_shapely.x, ingress_point_shapely.y - ) - - patrol_start_waypoint = builder.nav( - patrol_start, patrol_altitude, use_agl_patrol_altitude - ) - patrol_start_waypoint.name = "FLOT START" - patrol_start_waypoint.pretty_name = "FLOT start" - patrol_start_waypoint.description = "FLOT boundary" - patrol_start_waypoint.wants_escort = True - - patrol_end_waypoint = builder.nav( - patrol_end, patrol_altitude, use_agl_patrol_altitude - ) - patrol_end_waypoint.name = "FLOT END" - patrol_end_waypoint.pretty_name = "FLOT end" - patrol_end_waypoint.description = "FLOT boundary" - patrol_end_waypoint.wants_escort = True - - ingress = builder.ingress( - FlightWaypointType.INGRESS_CAS, ingress_point, location - ) - ingress.description = f"Ingress to provide CAS at {location}" - - return CasLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, - ingress_point, - patrol_altitude, - use_agl_patrol_altitude, - ), - nav_from=builder.nav_path( - patrol_end, - self.flight.arrival.position, - patrol_altitude, - use_agl_patrol_altitude, - ), - ingress=ingress, - patrol_start=patrol_start_waypoint, - patrol_end=patrol_end_waypoint, - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> CasFlightPlan: - return CasFlightPlan(self.flight, self.layout(dump_debug_info)) diff --git a/game/ato/flightplans/custom.py b/game/ato/flightplans/custom.py deleted file mode 100644 index abb3454f1..000000000 --- a/game/ato/flightplans/custom.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime -from typing import TYPE_CHECKING, Type - -from .flightplan import FlightPlan, Layout -from .ibuilder import IBuilder -from .waypointbuilder import WaypointBuilder -from .. import Flight -from ..flightwaypointtype import FlightWaypointType - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class CustomLayout(Layout): - custom_waypoints: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.custom_waypoints - - -class CustomFlightPlan(FlightPlan[CustomLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def tot_waypoint(self) -> FlightWaypoint: - target_types = ( - FlightWaypointType.PATROL_TRACK, - FlightWaypointType.TARGET_GROUP_LOC, - FlightWaypointType.TARGET_POINT, - FlightWaypointType.TARGET_SHIP, - ) - for waypoint in self.waypoints: - if waypoint in target_types: - return waypoint - return self.layout.departure - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.tot_waypoint: - return self.package.time_over_target - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.package.time_over_target - - -class Builder(IBuilder[CustomFlightPlan, CustomLayout]): - def __init__( - self, flight: Flight, waypoints: list[FlightWaypoint] | None = None - ) -> None: - super().__init__(flight) - if waypoints is None: - waypoints = [] - self.waypoints = waypoints - - def layout(self) -> CustomLayout: - builder = WaypointBuilder(self.flight, self.coalition) - return CustomLayout(builder.takeoff(self.flight.departure), self.waypoints) - - def build(self, dump_debug_info: bool = False) -> CustomFlightPlan: - return CustomFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/dead.py b/game/ato/flightplans/dead.py deleted file mode 100644 index 7f240cedb..000000000 --- a/game/ato/flightplans/dead.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import annotations - -import logging -from typing import Type - -from game.theater.theatergroundobject import ( - EwrGroundObject, - SamGroundObject, -) -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from ..flightwaypointtype import FlightWaypointType - - -class DeadFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[DeadFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - is_ewr = isinstance(location, EwrGroundObject) - is_sam = isinstance(location, SamGroundObject) - if not is_ewr and not is_sam: - logging.exception( - f"Invalid Objective Location for DEAD flight {self.flight=} at " - f"{location=}" - ) - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - return self._build(FlightWaypointType.INGRESS_DEAD) - - def build(self, dump_debug_info: bool = False) -> DeadFlightPlan: - return DeadFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/escort.py b/game/ato/flightplans/escort.py deleted file mode 100644 index 3d52466d4..000000000 --- a/game/ato/flightplans/escort.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -from typing import Type - -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .waypointbuilder import WaypointBuilder - - -class EscortFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - assert self.package.waypoints is not None - - builder = WaypointBuilder(self.flight, self.coalition) - ingress, target = builder.escort( - self.package.waypoints.ingress, self.package.target - ) - hold = builder.hold(self._hold_point()) - join = builder.join(self.package.waypoints.join) - split = builder.split(self.package.waypoints.split) - refuel = builder.refuel(self.package.waypoints.refuel) - - return FormationAttackLayout( - departure=builder.takeoff(self.flight.departure), - hold=hold, - nav_to=builder.nav_path( - hold.position, join.position, self.doctrine.combat_altitude - ), - join=join, - ingress=ingress, - targets=[target], - split=split, - refuel=refuel, - nav_from=builder.nav_path( - refuel.position, - self.flight.arrival.position, - self.doctrine.combat_altitude, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> EscortFlightPlan: - return EscortFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/ferry.py b/game/ato/flightplans/ferry.py deleted file mode 100644 index e7c2f3b38..000000000 --- a/game/ato/flightplans/ferry.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime -from typing import TYPE_CHECKING, Type - -from game.utils import feet -from .ibuilder import IBuilder -from .planningerror import PlanningError -from .standard import StandardFlightPlan, StandardLayout -from .waypointbuilder import WaypointBuilder - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class FerryLayout(StandardLayout): - nav_to_destination: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to_destination - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class FerryFlightPlan(StandardFlightPlan[FerryLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.arrival - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - # TOT planning isn't really useful for ferries. They're behind the front - # lines so no need to wait for escorts or for other missions to complete. - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.package.time_over_target - - -class Builder(IBuilder[FerryFlightPlan, FerryLayout]): - def layout(self) -> FerryLayout: - if self.flight.departure == self.flight.arrival: - raise PlanningError( - f"Cannot plan ferry self.flight: departure and arrival are both " - f"{self.flight.departure}" - ) - - altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter - altitude = ( - feet(1500) - if altitude_is_agl - else self.flight.unit_type.preferred_patrol_altitude - ) - - builder = WaypointBuilder(self.flight, self.coalition) - return FerryLayout( - departure=builder.takeoff(self.flight.departure), - nav_to_destination=builder.nav_path( - self.flight.departure.position, - self.flight.arrival.position, - altitude, - altitude_is_agl, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> FerryFlightPlan: - return FerryFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/flightplan.py b/game/ato/flightplans/flightplan.py deleted file mode 100644 index 5c1e1618f..000000000 --- a/game/ato/flightplans/flightplan.py +++ /dev/null @@ -1,290 +0,0 @@ -"""Flight plan generation. - -Flights are first planned generically by either the player or by the -MissionPlanner. Those only plan basic information like the objective, aircraft -type, and the size of the flight. The FlightPlanBuilder is responsible for -generating the waypoints for the mission. -""" -from __future__ import annotations - -import math -from abc import ABC, abstractmethod -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import Any, Generic, TYPE_CHECKING, TypeGuard, TypeVar - -from game.typeguard import self_type_guard -from game.utils import Distance, Speed, meters -from .planningerror import PlanningError -from ..flightwaypointtype import FlightWaypointType -from ..starttype import StartType -from ..traveltime import GroundSpeed - -if TYPE_CHECKING: - from game.theater import ControlPoint - from ..flight import Flight - from ..flightwaypoint import FlightWaypoint - from ..package import Package - from .formation import FormationFlightPlan - from .loiter import LoiterFlightPlan - from .patrolling import PatrollingFlightPlan - - -@dataclass(frozen=True) -class Layout(ABC): - departure: FlightWaypoint - - @property - def waypoints(self) -> list[FlightWaypoint]: - """A list of all waypoints in the flight plan, in order.""" - return list(self.iter_waypoints()) - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - """Iterates over all waypoints in the flight plan, in order.""" - raise NotImplementedError - - -LayoutT = TypeVar("LayoutT", bound=Layout) - - -class FlightPlan(ABC, Generic[LayoutT]): - def __init__(self, flight: Flight, layout: LayoutT) -> None: - self.flight = flight - self.layout = layout - self.tot_offset = self.default_tot_offset() - - @property - def package(self) -> Package: - return self.flight.package - - @property - def waypoints(self) -> list[FlightWaypoint]: - """A list of all waypoints in the flight plan, in order.""" - return list(self.iter_waypoints()) - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - """Iterates over all waypoints in the flight plan, in order.""" - yield from self.layout.iter_waypoints() - - def edges( - self, until: FlightWaypoint | None = None - ) -> Iterator[tuple[FlightWaypoint, FlightWaypoint]]: - """A list of all paths between waypoints, in order.""" - waypoints = self.waypoints - if until is None: - last_index = len(waypoints) - else: - last_index = waypoints.index(until) + 1 - - return zip(self.waypoints[:last_index], self.waypoints[1:last_index]) - - def best_speed_between_waypoints( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> Speed: - """Desired ground speed between points a and b.""" - factor = 1.0 - if b.waypoint_type == FlightWaypointType.ASCEND_POINT: - # Flights that start airborne already have some altitude and a good - # amount of speed. - factor = 0.5 - elif b.waypoint_type == FlightWaypointType.LOITER: - # On the way to the hold point the AI won't climb unless they're in - # formation, so slowing down the flight lead gives them more time to - # form up and climb. - # https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/dcs-wishlist-aa/7121300-ai-flights-will-not-climb-to-hold-point-because-wingman-not-joined - # - # Plus, it's a loiter point so there's no reason to hurry. - factor = 0.75 - # TODO: Adjust if AGL. - # We don't have an exact heightmap, but we should probably be performing - # *some* adjustment for NTTR since the minimum altitude of the map is - # near 2000 ft MSL. - return GroundSpeed.for_flight(self.flight, min(a.alt, b.alt)) * factor - - def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed: - return self.best_speed_between_waypoints(a, b) - - @property - def combat_speed_waypoints(self) -> set[FlightWaypoint]: - return set() - - def fuel_consumption_between_points( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> float | None: - ppm = self.fuel_rate_to_between_points(a, b) - if ppm is None: - return None - distance = meters(a.position.distance_to_point(b.position)) - return distance.nautical_miles * ppm - - def fuel_rate_to_between_points( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> float | None: - if self.flight.unit_type.fuel_consumption is None: - return None - if a.waypoint_type is FlightWaypointType.TAKEOFF: - return self.flight.unit_type.fuel_consumption.climb - if b in self.combat_speed_waypoints: - return self.flight.unit_type.fuel_consumption.combat - return self.flight.unit_type.fuel_consumption.cruise - - @property - def tot_waypoint(self) -> FlightWaypoint: - """The waypoint that is associated with the package TOT, or None. - - Note that the only flight plans that should have no target waypoints are - user-planned missions without any useful waypoints and flight plans that - failed to generate. Nevertheless, we have to defend against it. - """ - raise NotImplementedError - - @property - def tot(self) -> datetime: - return self.package.time_over_target + self.tot_offset - - def max_distance_from(self, cp: ControlPoint) -> Distance: - """Returns the farthest waypoint of the flight plan from a ControlPoint. - :arg cp The ControlPoint to measure distance from. - """ - if not self.waypoints: - return meters(0) - return max( - [meters(cp.position.distance_to_point(w.position)) for w in self.waypoints] - ) - - def default_tot_offset(self) -> timedelta: - """This flight's offset from the package's TOT. - - Positive values represent later TOTs. An offset of -2 minutes is used - for a flight that has a TOT 2 minutes before the rest of the package. - """ - return timedelta() - - def _travel_time_to_waypoint(self, destination: FlightWaypoint) -> timedelta: - total = timedelta() - - if destination not in self.waypoints: - raise PlanningError( - f"Did not find destination waypoint {destination} in " - f"waypoints for {self.flight}" - ) - - for previous_waypoint, waypoint in self.edges(until=destination): - total += self.total_time_between_waypoints(previous_waypoint, waypoint) - - # Trim microseconds. Our simulation tick rate is 1 second, so anything that - # takes 100.1 or 100.9 seconds will take 100 seconds. DCS doesn't handle - # sub-second resolution for tasks anyway, nor are they interesting from a - # mission planning perspective, so there's little value to keeping them in the - # model. - return timedelta(seconds=math.floor(total.total_seconds())) - - def total_time_between_waypoints( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> timedelta: - """Returns the total time spent between a and b. - - The total time between waypoints differs from the travel time in that it may - include additional time for actions such as loitering. - """ - return self.travel_time_between_waypoints(a, b) - - def travel_time_between_waypoints( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> timedelta: - error_factor = 1.05 - speed = self.speed_between_waypoints(a, b) - distance = meters(a.position.distance_to_point(b.position)) - return timedelta(hours=distance.nautical_miles / speed.knots * error_factor) - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - raise NotImplementedError - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - raise NotImplementedError - - def request_escort_at(self) -> FlightWaypoint | None: - try: - return next(self.escorted_waypoints()) - except StopIteration: - return None - - def dismiss_escort_at(self) -> FlightWaypoint | None: - try: - return list(self.escorted_waypoints())[-1] - except IndexError: - return None - - def escorted_waypoints(self) -> Iterator[FlightWaypoint]: - for waypoint in self.iter_waypoints(): - if waypoint.wants_escort: - yield waypoint - - def takeoff_time(self) -> datetime: - return self.tot - self._travel_time_to_waypoint(self.tot_waypoint) - - def minimum_duration_from_start_to_tot(self) -> timedelta: - return ( - self._travel_time_to_waypoint(self.tot_waypoint) - + self.estimate_startup() - + self.estimate_ground_ops() - ) - - def startup_time(self) -> datetime: - return ( - self.takeoff_time() - self.estimate_startup() - self.estimate_ground_ops() - ) - - def estimate_startup(self) -> timedelta: - if self.flight.start_type is StartType.COLD: - if self.flight.client_count: - return timedelta(minutes=10) - else: - # The AI doesn't seem to have a real startup procedure. - return timedelta(minutes=2) - return timedelta() - - def estimate_ground_ops(self) -> timedelta: - if self.flight.start_type in {StartType.RUNWAY, StartType.IN_FLIGHT}: - return timedelta() - if self.flight.departure.is_fleet: - return timedelta(minutes=2) - else: - return timedelta(minutes=8) - - @property - @abstractmethod - def mission_begin_on_station_time(self) -> datetime | None: - """The time that the mission is first on-station. - - Not all mission types will have a time when they can be considered on-station. - Missions that patrol or loiter (CAPs, CAS, refueling, AEW&C, etc) will have this - defined, but strike-like missions will not. - """ - - @property - def mission_departure_time(self) -> datetime: - """The time that the mission is complete and the flight RTBs.""" - raise NotImplementedError - - @self_type_guard - def is_loiter( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[LoiterFlightPlan[Any]]: - return False - - @self_type_guard - def is_patrol( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[PatrollingFlightPlan[Any]]: - return False - - @self_type_guard - def is_formation( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[FormationFlightPlan[Any]]: - return False - - def add_waypoint_actions(self) -> None: - pass diff --git a/game/ato/flightplans/flightplanbuildertypes.py b/game/ato/flightplans/flightplanbuildertypes.py deleted file mode 100644 index 45d9ca560..000000000 --- a/game/ato/flightplans/flightplanbuildertypes.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from typing import Any, TYPE_CHECKING, Type - -from game.ato import FlightType -from game.theater.controlpoint import NavalControlPoint -from game.theater.frontline import FrontLine -from .aewc import AewcFlightPlan -from .airassault import AirAssaultFlightPlan -from .airlift import AirliftFlightPlan -from .antiship import AntiShipFlightPlan -from .bai import BaiFlightPlan -from .barcap import BarCapFlightPlan -from .cas import CasFlightPlan -from .dead import DeadFlightPlan -from .escort import EscortFlightPlan -from .ferry import FerryFlightPlan -from .ibuilder import IBuilder -from .ocaaircraft import OcaAircraftFlightPlan -from .ocarunway import OcaRunwayFlightPlan -from .packagerefueling import PackageRefuelingFlightPlan -from .planningerror import PlanningError -from .sead import SeadFlightPlan -from .shiprecoverytanker import RecoveryTankerFlightPlan -from .strike import StrikeFlightPlan -from .sweep import SweepFlightPlan -from .tarcap import TarCapFlightPlan -from .theaterrefueling import TheaterRefuelingFlightPlan - -if TYPE_CHECKING: - from game.ato import Flight - - -class FlightPlanBuilderTypes: - @staticmethod - def for_flight(flight: Flight) -> Type[IBuilder[Any, Any]]: - if flight.flight_type is FlightType.REFUELING: - target = flight.package.target - if target.is_friendly(flight.squadron.player) and isinstance( - target, NavalControlPoint - ): - return RecoveryTankerFlightPlan.builder_type() - if target.is_friendly(flight.squadron.player) or isinstance( - target, FrontLine - ): - return TheaterRefuelingFlightPlan.builder_type() - return PackageRefuelingFlightPlan.builder_type() - - builder_dict: dict[FlightType, Type[IBuilder[Any, Any]]] = { - FlightType.ANTISHIP: AntiShipFlightPlan.builder_type(), - FlightType.BAI: BaiFlightPlan.builder_type(), - FlightType.BARCAP: BarCapFlightPlan.builder_type(), - FlightType.CAS: CasFlightPlan.builder_type(), - FlightType.DEAD: DeadFlightPlan.builder_type(), - FlightType.ESCORT: EscortFlightPlan.builder_type(), - FlightType.OCA_AIRCRAFT: OcaAircraftFlightPlan.builder_type(), - FlightType.OCA_RUNWAY: OcaRunwayFlightPlan.builder_type(), - FlightType.SEAD: SeadFlightPlan.builder_type(), - FlightType.SEAD_ESCORT: EscortFlightPlan.builder_type(), - FlightType.STRIKE: StrikeFlightPlan.builder_type(), - FlightType.SWEEP: SweepFlightPlan.builder_type(), - FlightType.TARCAP: TarCapFlightPlan.builder_type(), - FlightType.AEWC: AewcFlightPlan.builder_type(), - FlightType.TRANSPORT: AirliftFlightPlan.builder_type(), - FlightType.FERRY: FerryFlightPlan.builder_type(), - FlightType.AIR_ASSAULT: AirAssaultFlightPlan.builder_type(), - } - try: - return builder_dict[flight.flight_type] - except KeyError as ex: - raise PlanningError( - f"{flight.flight_type} flight plan generation not implemented" - ) from ex diff --git a/game/ato/flightplans/formation.py b/game/ato/flightplans/formation.py deleted file mode 100644 index 4ba8ab1c9..000000000 --- a/game/ato/flightplans/formation.py +++ /dev/null @@ -1,105 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from datetime import datetime, timedelta -from functools import cached_property -from typing import Any, TYPE_CHECKING, TypeGuard, TypeVar - -from game.typeguard import self_type_guard -from game.utils import Speed -from .flightplan import FlightPlan -from .loiter import LoiterFlightPlan, LoiterLayout - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class FormationLayout(LoiterLayout, ABC): - nav_to: list[FlightWaypoint] - join: FlightWaypoint - split: FlightWaypoint - refuel: FlightWaypoint - nav_from: list[FlightWaypoint] - - -LayoutT = TypeVar("LayoutT", bound=FormationLayout) - - -class FormationFlightPlan(LoiterFlightPlan[LayoutT], ABC): - @property - @abstractmethod - def package_speed_waypoints(self) -> set[FlightWaypoint]: - ... - - @property - def combat_speed_waypoints(self) -> set[FlightWaypoint]: - return self.package_speed_waypoints - - @cached_property - def best_flight_formation_speed(self) -> Speed: - """The best speed this flight is capable at all formation waypoints. - - To ease coordination with other flights, we aim to have a single mission - speed used by the formation for all waypoints. As such, this function - returns the highest ground speed that the flight is capable of flying at - all of its formation waypoints. - """ - speeds = [] - for previous_waypoint, waypoint in self.edges(): - if waypoint in self.package_speed_waypoints: - speeds.append( - self.best_speed_between_waypoints(previous_waypoint, waypoint) - ) - return min(speeds) - - def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed: - if b in self.package_speed_waypoints: - # Should be impossible, as any package with at least one - # FormationFlightPlan flight needs a formation speed. - assert self.package.formation_speed is not None - return self.package.formation_speed - return super().speed_between_waypoints(a, b) - - @property - def travel_time_to_rendezvous(self) -> timedelta: - """The estimated time between the first waypoint and the join point.""" - return self._travel_time_to_waypoint(self.layout.join) - - @property - @abstractmethod - def join_time(self) -> datetime: - ... - - @property - @abstractmethod - def split_time(self) -> datetime: - ... - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.join: - return self.join_time - elif waypoint == self.layout.split: - return self.split_time - return None - - @property - def push_time(self) -> datetime: - return self.join_time - self.travel_time_between_waypoints( - self.layout.hold, self.layout.join - ) - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.split_time - - @self_type_guard - def is_formation( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[FormationFlightPlan[Any]]: - return True diff --git a/game/ato/flightplans/formationattack.py b/game/ato/flightplans/formationattack.py deleted file mode 100644 index bd19b1c04..000000000 --- a/game/ato/flightplans/formationattack.py +++ /dev/null @@ -1,217 +0,0 @@ -from __future__ import annotations - -from abc import ABC -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import TYPE_CHECKING, TypeVar - -from dcs import Point - -from game.flightplan import HoldZoneGeometry -from game.theater import MissionTarget -from game.utils import Speed, meters -from .flightplan import FlightPlan -from .formation import FormationFlightPlan, FormationLayout -from .ibuilder import IBuilder -from .waypointbuilder import StrikeTarget, WaypointBuilder -from .. import FlightType -from ..flightwaypoint import FlightWaypoint -from ..flightwaypointtype import FlightWaypointType - -if TYPE_CHECKING: - from ..flight import Flight - - -@dataclass(frozen=True) -class FormationAttackLayout(FormationLayout): - ingress: FlightWaypoint - targets: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield self.hold - yield from self.nav_to - yield self.join - yield self.ingress - yield from self.targets - yield self.split - if self.refuel is not None: - yield self.refuel - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class FormationAttackFlightPlan(FormationFlightPlan[FormationAttackLayout], ABC): - @property - def package_speed_waypoints(self) -> set[FlightWaypoint]: - return { - self.layout.ingress, - self.layout.split, - } | set(self.layout.targets) - - def speed_between_waypoints(self, a: FlightWaypoint, b: FlightWaypoint) -> Speed: - # FlightWaypoint is only comparable by identity, so adding - # target_area_waypoint to package_speed_waypoints is useless. - if b.waypoint_type == FlightWaypointType.TARGET_GROUP_LOC: - # Should be impossible, as any package with at least one - # FormationFlightPlan flight needs a formation speed. - assert self.package.formation_speed is not None - return self.package.formation_speed - return super().speed_between_waypoints(a, b) - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.targets[0] - - @property - def target_area_waypoint(self) -> FlightWaypoint: - return FlightWaypoint( - "TARGET AREA", - FlightWaypointType.TARGET_GROUP_LOC, - self.package.target.position, - meters(0), - "RADIO", - ) - - @property - def join_time(self) -> datetime: - travel_time = self.total_time_between_waypoints( - self.layout.join, self.layout.ingress - ) - return self.ingress_time - travel_time - - @property - def split_time(self) -> datetime: - travel_time_ingress = self.total_time_between_waypoints( - self.layout.ingress, self.target_area_waypoint - ) - travel_time_egress = self.total_time_between_waypoints( - self.target_area_waypoint, self.layout.split - ) - minutes_at_target = 0.75 * len(self.layout.targets) - timedelta_at_target = timedelta(minutes=minutes_at_target) - return ( - self.ingress_time - + travel_time_ingress - + timedelta_at_target - + travel_time_egress - ) - - @property - def ingress_time(self) -> datetime: - tot = self.tot - travel_time = self.total_time_between_waypoints( - self.layout.ingress, self.target_area_waypoint - ) - return tot - travel_time - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.ingress: - return self.ingress_time - elif waypoint in self.layout.targets: - return self.tot - return super().tot_for_waypoint(waypoint) - - -FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[FormationAttackLayout]) -LayoutT = TypeVar("LayoutT", bound=FormationAttackLayout) - - -class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC): - def _build( - self, - ingress_type: FlightWaypointType, - targets: list[StrikeTarget] | None = None, - ) -> FormationAttackLayout: - assert self.package.waypoints is not None - builder = WaypointBuilder(self.flight, self.coalition, targets) - - target_waypoints: list[FlightWaypoint] = [] - if targets is not None: - for target in targets: - target_waypoints.append( - self.target_waypoint(self.flight, builder, target) - ) - else: - target_waypoints.append( - self.target_area_waypoint( - self.flight, self.flight.package.target, builder - ) - ) - - hold = builder.hold(self._hold_point()) - join = builder.join(self.package.waypoints.join) - join.wants_escort = True - - ingress = builder.ingress( - ingress_type, self.package.waypoints.ingress, self.package.target - ) - ingress.wants_escort = True - - for target_waypoint in target_waypoints: - target_waypoint.wants_escort = True - - split = builder.split(self.package.waypoints.split) - split.wants_escort = True - refuel = builder.refuel(self.package.waypoints.refuel) - - return FormationAttackLayout( - departure=builder.takeoff(self.flight.departure), - hold=hold, - nav_to=builder.nav_path( - hold.position, join.position, self.doctrine.combat_altitude - ), - join=join, - ingress=ingress, - targets=target_waypoints, - split=split, - refuel=refuel, - nav_from=builder.nav_path( - refuel.position, - self.flight.arrival.position, - self.doctrine.combat_altitude, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - @staticmethod - def target_waypoint( - flight: Flight, builder: WaypointBuilder, target: StrikeTarget - ) -> FlightWaypoint: - if flight.flight_type in {FlightType.ANTISHIP, FlightType.BAI}: - return builder.bai_group(target) - elif flight.flight_type == FlightType.DEAD: - return builder.dead_point(target) - elif flight.flight_type == FlightType.SEAD: - return builder.sead_point(target) - else: - return builder.strike_point(target) - - @staticmethod - def target_area_waypoint( - flight: Flight, location: MissionTarget, builder: WaypointBuilder - ) -> FlightWaypoint: - if flight.flight_type == FlightType.DEAD: - return builder.dead_area(location) - elif flight.flight_type == FlightType.SEAD: - return builder.sead_area(location) - elif flight.flight_type == FlightType.OCA_AIRCRAFT: - return builder.oca_strike_area(location) - else: - return builder.strike_area(location) - - def _hold_point(self) -> Point: - assert self.package.waypoints is not None - origin = self.flight.departure.position - target = self.package.target.position - join = self.package.waypoints.join - ip = self.package.waypoints.ingress - return HoldZoneGeometry( - target, origin, ip, join, self.coalition, self.theater - ).find_best_hold_point() diff --git a/game/ato/flightplans/ibuilder.py b/game/ato/flightplans/ibuilder.py deleted file mode 100644 index 25ea3157a..000000000 --- a/game/ato/flightplans/ibuilder.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Any, Generic, TYPE_CHECKING, TypeVar - -from game.navmesh import NavMeshError -from .flightplan import FlightPlan, Layout -from .planningerror import PlanningError -from ..packagewaypoints import PackageWaypoints - -if TYPE_CHECKING: - from game.coalition import Coalition - from game.data.doctrine import Doctrine - from game.theater import ConflictTheater - from game.threatzones import ThreatZones - from ..flight import Flight - from ..package import Package - - -FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[Any]) -LayoutT = TypeVar("LayoutT", bound=Layout) - - -class IBuilder(ABC, Generic[FlightPlanT, LayoutT]): - def __init__(self, flight: Flight) -> None: - self.flight = flight - self._flight_plan: FlightPlanT | None = None - - def get_or_build(self) -> FlightPlanT: - if self._flight_plan is None: - self.regenerate() - assert self._flight_plan is not None - return self._flight_plan - - def regenerate(self, dump_debug_info: bool = False) -> None: - try: - self._generate_package_waypoints_if_needed(dump_debug_info) - self._flight_plan = self.build(dump_debug_info) - self._flight_plan.add_waypoint_actions() - except NavMeshError as ex: - color = "blue" if self.flight.squadron.player else "red" - raise PlanningError( - f"Could not plan {color} {self.flight.flight_type.value} from " - f"{self.flight.departure} to {self.package.target}" - ) from ex - - def _generate_package_waypoints_if_needed(self, dump_debug_info: bool) -> None: - # Package waypoints are only valid for offensive missions. Skip this if the - # target is friendly. - if self.package.target.is_friendly(self.is_player): - return - - if self.package.waypoints is None or dump_debug_info: - self.package.waypoints = PackageWaypoints.create( - self.package, self.coalition, dump_debug_info - ) - - @property - def theater(self) -> ConflictTheater: - return self.flight.departure.theater - - @abstractmethod - def build(self, dump_debug_info: bool = False) -> FlightPlanT: - ... - - @property - def package(self) -> Package: - return self.flight.package - - @property - def coalition(self) -> Coalition: - return self.flight.coalition - - @property - def is_player(self) -> bool: - return self.coalition.player - - @property - def doctrine(self) -> Doctrine: - return self.coalition.doctrine - - @property - def threat_zones(self) -> ThreatZones: - return self.coalition.opponent.threat_zone diff --git a/game/ato/flightplans/invalidobjectivelocation.py b/game/ato/flightplans/invalidobjectivelocation.py deleted file mode 100644 index fe4eedbb5..000000000 --- a/game/ato/flightplans/invalidobjectivelocation.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -from game.ato import FlightType -from game.ato.flightplans.planningerror import PlanningError -from game.theater import MissionTarget - - -class InvalidObjectiveLocation(PlanningError): - """Raised when the objective location is invalid for the mission type.""" - - def __init__(self, task: FlightType, location: MissionTarget) -> None: - super().__init__(f"{location.name} is not valid for {task} missions.") diff --git a/game/ato/flightplans/loiter.py b/game/ato/flightplans/loiter.py deleted file mode 100644 index 4d6e9dce3..000000000 --- a/game/ato/flightplans/loiter.py +++ /dev/null @@ -1,63 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import Any, TYPE_CHECKING, TypeGuard, TypeVar - -from game.flightplan.waypointactions.hold import Hold -from game.typeguard import self_type_guard -from game.utils import Speed -from .flightplan import FlightPlan -from .standard import StandardFlightPlan, StandardLayout - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class LoiterLayout(StandardLayout, ABC): - hold: FlightWaypoint - - -LayoutT = TypeVar("LayoutT", bound=LoiterLayout) - - -class LoiterFlightPlan(StandardFlightPlan[LayoutT], ABC): - @property - def hold_duration(self) -> timedelta: - return timedelta(minutes=5) - - @property - @abstractmethod - def push_time(self) -> datetime: - ... - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.hold: - return self.push_time - return None - - def total_time_between_waypoints( - self, a: FlightWaypoint, b: FlightWaypoint - ) -> timedelta: - travel_time = super().total_time_between_waypoints(a, b) - if a != self.layout.hold: - return travel_time - return travel_time + self.hold_duration - - @self_type_guard - def is_loiter( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[LoiterFlightPlan[Any]]: - return True - - def provide_push_time(self) -> datetime: - return self.push_time - - def add_waypoint_actions(self) -> None: - hold = self.layout.hold - speed = self.flight.unit_type.patrol_speed - if speed is None: - speed = Speed.from_mach(0.6, hold.alt) - hold.add_action(Hold(self.provide_push_time, hold.alt, speed)) diff --git a/game/ato/flightplans/ocaaircraft.py b/game/ato/flightplans/ocaaircraft.py deleted file mode 100644 index 61cffce1c..000000000 --- a/game/ato/flightplans/ocaaircraft.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import annotations - -import logging -from typing import Type - -from game.theater import Airfield -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from ..flightwaypointtype import FlightWaypointType - - -class OcaAircraftFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[OcaAircraftFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - if not isinstance(location, Airfield): - logging.exception( - f"Invalid Objective Location for OCA/Aircraft flight " - f"{self.flight=} at {location=}." - ) - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - return self._build(FlightWaypointType.INGRESS_OCA_AIRCRAFT) - - def build(self, dump_debug_info: bool = False) -> OcaAircraftFlightPlan: - return OcaAircraftFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/ocarunway.py b/game/ato/flightplans/ocarunway.py deleted file mode 100644 index 234d8f417..000000000 --- a/game/ato/flightplans/ocarunway.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import annotations - -import logging -from typing import Type - -from game.theater import Airfield -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from ..flightwaypointtype import FlightWaypointType - - -class OcaRunwayFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[OcaRunwayFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - if not isinstance(location, Airfield): - logging.exception( - f"Invalid Objective Location for OCA/Runway flight " - f"{self.flight=} at {location=}." - ) - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - return self._build(FlightWaypointType.INGRESS_OCA_RUNWAY) - - def build(self, dump_debug_info: bool = False) -> OcaRunwayFlightPlan: - return OcaRunwayFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/packagerefueling.py b/game/ato/flightplans/packagerefueling.py deleted file mode 100644 index 1698f7c70..000000000 --- a/game/ato/flightplans/packagerefueling.py +++ /dev/null @@ -1,125 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import Type - -from dcs import Point - -from game.utils import Distance, Heading, feet, meters -from .ibuilder import IBuilder -from .patrolling import PatrollingLayout -from .refuelingflightplan import RefuelingFlightPlan -from .waypointbuilder import WaypointBuilder -from ..flightwaypoint import FlightWaypoint -from ..flightwaypointtype import FlightWaypointType - - -class PackageRefuelingFlightPlan(RefuelingFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def patrol_duration(self) -> timedelta: - # TODO: Only consider aircraft that can refuel with this tanker type. - refuel_time_minutes = 5 - for self.flight in self.package.flights: - flight_size = self.flight.roster.max_size - refuel_time_minutes = refuel_time_minutes + 4 * flight_size + 1 - - return timedelta(minutes=refuel_time_minutes) - - def target_area_waypoint(self) -> FlightWaypoint: - return FlightWaypoint( - "TARGET AREA", - FlightWaypointType.TARGET_GROUP_LOC, - self.package.target.position, - meters(0), - "RADIO", - ) - - @property - def patrol_start_time(self) -> datetime: - altitude = self.flight.unit_type.patrol_altitude - - if altitude is None: - altitude = Distance.from_feet(20000) - - assert self.package.waypoints is not None - - # Cheat in a FlightWaypoint for the split point. - split: Point = self.package.waypoints.split - split_waypoint: FlightWaypoint = FlightWaypoint( - "SPLIT", FlightWaypointType.SPLIT, split, altitude - ) - - # Cheat in a FlightWaypoint for the refuel point. - refuel: Point = self.package.waypoints.refuel - refuel_waypoint: FlightWaypoint = FlightWaypoint( - "REFUEL", FlightWaypointType.REFUEL, refuel, altitude - ) - - delay_target_to_split: timedelta = self.total_time_between_waypoints( - self.target_area_waypoint(), split_waypoint - ) - delay_split_to_refuel: timedelta = self.total_time_between_waypoints( - split_waypoint, refuel_waypoint - ) - - return ( - self.package.time_over_target - + delay_target_to_split - + delay_split_to_refuel - - timedelta(minutes=1.5) - ) - - -class Builder(IBuilder[PackageRefuelingFlightPlan, PatrollingLayout]): - def layout(self) -> PatrollingLayout: - package_waypoints = self.package.waypoints - assert package_waypoints is not None - - racetrack_half_distance = Distance.from_nautical_miles(20).meters - - racetrack_center = package_waypoints.refuel - - split_heading = Heading.from_degrees( - racetrack_center.heading_between_point(package_waypoints.split) - ) - home_heading = split_heading.opposite - - racetrack_start = racetrack_center.point_from_heading( - split_heading.degrees, racetrack_half_distance - ) - - racetrack_end = racetrack_center.point_from_heading( - home_heading.degrees, racetrack_half_distance - ) - - builder = WaypointBuilder(self.flight, self.coalition) - - tanker_type = self.flight.unit_type - if tanker_type.patrol_altitude is not None: - altitude = tanker_type.patrol_altitude - else: - altitude = feet(21000) - - racetrack = builder.race_track(racetrack_start, racetrack_end, altitude) - - return PatrollingLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, racetrack_start, altitude - ), - nav_from=builder.nav_path( - racetrack_end, self.flight.arrival.position, altitude - ), - patrol_start=racetrack[0], - patrol_end=racetrack[1], - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> PackageRefuelingFlightPlan: - return PackageRefuelingFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/patrolling.py b/game/ato/flightplans/patrolling.py deleted file mode 100644 index a2ee3f605..000000000 --- a/game/ato/flightplans/patrolling.py +++ /dev/null @@ -1,110 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import Any, TYPE_CHECKING, TypeGuard, TypeVar - -from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout -from game.typeguard import self_type_guard -from game.utils import Distance, Speed -from .uizonedisplay import UiZone, UiZoneDisplay - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - from .flightplan import FlightPlan - - -@dataclass(frozen=True) -class PatrollingLayout(StandardLayout): - nav_to: list[FlightWaypoint] - patrol_start: FlightWaypoint - patrol_end: FlightWaypoint - nav_from: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to - yield self.patrol_start - yield self.patrol_end - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -LayoutT = TypeVar("LayoutT", bound=PatrollingLayout) - - -class PatrollingFlightPlan(StandardFlightPlan[LayoutT], UiZoneDisplay, ABC): - @property - @abstractmethod - def patrol_duration(self) -> timedelta: - """Maximum time to remain on station.""" - - @property - @abstractmethod - def patrol_speed(self) -> Speed: - """Racetrack speed TAS.""" - - @property - @abstractmethod - def engagement_distance(self) -> Distance: - """The maximum engagement distance. - - The engagement range of any Search Then Engage task, or the radius of a Search - Then Engage in Zone task. Any enemies of the appropriate type for this mission - within this range of the flight's current position (or the center of the zone) - will be engaged by the flight. - """ - - @property - def patrol_start_time(self) -> datetime: - return self.tot - - @property - def patrol_end_time(self) -> datetime: - # TODO: This is currently wrong for CAS. - # CAS missions end when they're winchester or bingo. We need to - # configure push tasks for the escorts rather than relying on timing. - return self.patrol_start_time + self.patrol_duration - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.patrol_start: - return self.patrol_start_time - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.patrol_end: - return self.patrol_end_time - return None - - @property - def package_speed_waypoints(self) -> set[FlightWaypoint]: - return {self.layout.patrol_start, self.layout.patrol_end} - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.patrol_start - - @property - def mission_begin_on_station_time(self) -> datetime: - return self.patrol_start_time - - @property - def mission_departure_time(self) -> datetime: - return self.patrol_end_time - - @self_type_guard - def is_patrol( - self, flight_plan: FlightPlan[Any] - ) -> TypeGuard[PatrollingFlightPlan[Any]]: - return True - - def ui_zone(self) -> UiZone: - return UiZone( - [self.layout.patrol_start.position, self.layout.patrol_end.position], - self.engagement_distance, - ) diff --git a/game/ato/flightplans/planningerror.py b/game/ato/flightplans/planningerror.py deleted file mode 100644 index d11c1baff..000000000 --- a/game/ato/flightplans/planningerror.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import annotations - - -class PlanningError(RuntimeError): - """Raised when the flight planner was unable to create a flight plan.""" diff --git a/game/ato/flightplans/refuelingflightplan.py b/game/ato/flightplans/refuelingflightplan.py deleted file mode 100644 index 2fb00d5be..000000000 --- a/game/ato/flightplans/refuelingflightplan.py +++ /dev/null @@ -1,20 +0,0 @@ -from abc import ABC - -from game.utils import Distance, Speed, knots, meters -from .patrolling import PatrollingFlightPlan, PatrollingLayout - - -class RefuelingFlightPlan(PatrollingFlightPlan[PatrollingLayout], ABC): - @property - def patrol_speed(self) -> Speed: - # TODO: Could use self.flight.unit_type.preferred_patrol_speed(altitude). - if self.flight.unit_type.patrol_speed is not None: - return self.flight.unit_type.patrol_speed - # ~280 knots IAS at 21000. - return knots(400) - - @property - def engagement_distance(self) -> Distance: - # TODO: Factor out a common base of the combat and non-combat race-tracks. - # No harm in setting this, but we ought to clean up a bit. - return meters(0) diff --git a/game/ato/flightplans/rtb.py b/game/ato/flightplans/rtb.py deleted file mode 100644 index 34fb0206d..000000000 --- a/game/ato/flightplans/rtb.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime -from typing import TYPE_CHECKING, Type - -from game.utils import feet -from .ibuilder import IBuilder -from .standard import StandardFlightPlan, StandardLayout -from .waypointbuilder import WaypointBuilder -from ..flightstate import InFlight - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class RtbLayout(StandardLayout): - abort_location: FlightWaypoint - nav_to_destination: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield self.abort_location - yield from self.nav_to_destination - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class RtbFlightPlan(StandardFlightPlan[RtbLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def abort_index(self) -> int: - return 1 - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.abort_location - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - return None - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.tot - - -class Builder(IBuilder[RtbFlightPlan, RtbLayout]): - def layout(self) -> RtbLayout: - if not isinstance(self.flight.state, InFlight): - raise RuntimeError(f"Cannot abort {self} because it is not in flight") - - current_position = self.flight.state.estimate_position() - current_altitude, altitude_reference = self.flight.state.estimate_altitude() - - altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter - altitude = ( - feet(1500) - if altitude_is_agl - else self.flight.unit_type.preferred_patrol_altitude - ) - builder = WaypointBuilder(self.flight, self.flight.coalition) - abort_point = builder.nav( - current_position, current_altitude, altitude_reference == "RADIO" - ) - abort_point.name = "ABORT AND RTB" - abort_point.pretty_name = "Abort and RTB" - abort_point.description = "Abort mission and return to base" - return RtbLayout( - departure=builder.takeoff(self.flight.departure), - abort_location=abort_point, - nav_to_destination=builder.nav_path( - current_position, - self.flight.arrival.position, - altitude, - altitude_is_agl, - ), - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> RtbFlightPlan: - return RtbFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/sead.py b/game/ato/flightplans/sead.py deleted file mode 100644 index 2a6910269..000000000 --- a/game/ato/flightplans/sead.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from datetime import timedelta -from typing import Type - -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from ..flightwaypointtype import FlightWaypointType - - -class SeadFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - def default_tot_offset(self) -> timedelta: - return -timedelta(minutes=1) - - -class Builder(FormationAttackBuilder[SeadFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - return self._build(FlightWaypointType.INGRESS_SEAD) - - def build(self, dump_debug_info: bool = False) -> SeadFlightPlan: - return SeadFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/shiprecoverytanker.py b/game/ato/flightplans/shiprecoverytanker.py deleted file mode 100644 index 54f734c1f..000000000 --- a/game/ato/flightplans/shiprecoverytanker.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import Iterator, Type - -from game.ato.flightplans.ibuilder import IBuilder -from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout -from game.ato.flightplans.waypointbuilder import WaypointBuilder -from game.ato.flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class RecoveryTankerLayout(StandardLayout): - nav_to: list[FlightWaypoint] - recovery_ship: FlightWaypoint - nav_from: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to - yield self.recovery_ship - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.recovery_ship - - @property - def mission_begin_on_station_time(self) -> datetime: - return self.package.time_over_target - - @property - def mission_departure_time(self) -> datetime: - return self.patrol_end_time - - @property - def patrol_start_time(self) -> datetime: - return self.package.time_over_target - - @property - def patrol_end_time(self) -> datetime: - return self.tot + timedelta(hours=2) - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.tot_waypoint: - return self.tot - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.tot_waypoint: - return self.mission_departure_time - return None - - -class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]): - def layout(self) -> RecoveryTankerLayout: - builder = WaypointBuilder(self.flight, self.coalition) - - # TODO: Propagate the ship position to the Tanker's TOT, - # so that we minimize the tanker's need to catch up to the carrier. - recovery_ship = self.package.target.position - recovery_tanker = builder.recovery_tanker(recovery_ship) - - # We don't have per aircraft cruise altitudes, so just reuse patrol altitude? - tanker_type = self.flight.unit_type - nav_cruise_altitude = tanker_type.preferred_patrol_altitude - - return RecoveryTankerLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, recovery_ship, nav_cruise_altitude - ), - nav_from=builder.nav_path( - recovery_ship, self.flight.arrival.position, nav_cruise_altitude - ), - recovery_ship=recovery_tanker, - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> RecoveryTankerFlightPlan: - return RecoveryTankerFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/standard.py b/game/ato/flightplans/standard.py deleted file mode 100644 index 5cc45f95e..000000000 --- a/game/ato/flightplans/standard.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from abc import ABC -from dataclasses import dataclass -from typing import TYPE_CHECKING, TypeVar - -from game.ato.flightplans.flightplan import FlightPlan, Layout - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class StandardLayout(Layout, ABC): - arrival: FlightWaypoint - divert: FlightWaypoint | None - bullseye: FlightWaypoint - - -LayoutT = TypeVar("LayoutT", bound=StandardLayout) - - -class StandardFlightPlan(FlightPlan[LayoutT], ABC): - """Base type for all non-custom flight plans. - - We can't reason about custom flight plans so they get special treatment, but all - others are guaranteed to have certain properties like departure and arrival points, - potentially a divert field, and a bullseye - """ diff --git a/game/ato/flightplans/strike.py b/game/ato/flightplans/strike.py deleted file mode 100644 index e04387c3b..000000000 --- a/game/ato/flightplans/strike.py +++ /dev/null @@ -1,36 +0,0 @@ -from __future__ import annotations - -from typing import Type - -from game.theater import TheaterGroundObject -from .formationattack import ( - FormationAttackBuilder, - FormationAttackFlightPlan, - FormationAttackLayout, -) -from .invalidobjectivelocation import InvalidObjectiveLocation -from .waypointbuilder import StrikeTarget -from ..flightwaypointtype import FlightWaypointType - - -class StrikeFlightPlan(FormationAttackFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - -class Builder(FormationAttackBuilder[StrikeFlightPlan, FormationAttackLayout]): - def layout(self) -> FormationAttackLayout: - location = self.package.target - - if not isinstance(location, TheaterGroundObject): - raise InvalidObjectiveLocation(self.flight.flight_type, location) - - targets: list[StrikeTarget] = [] - for idx, unit in enumerate(location.strike_targets): - targets.append(StrikeTarget(f"{unit.type.id} #{idx}", unit)) - - return self._build(FlightWaypointType.INGRESS_STRIKE, targets) - - def build(self, dump_debug_info: bool = False) -> StrikeFlightPlan: - return StrikeFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/sweep.py b/game/ato/flightplans/sweep.py deleted file mode 100644 index 7dddca7df..000000000 --- a/game/ato/flightplans/sweep.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import Iterator, TYPE_CHECKING, Type - -from dcs import Point -from dcs.task import Targets - -from game.flightplan import HoldZoneGeometry -from game.flightplan.waypointactions.engagetargets import EngageTargets -from game.flightplan.waypointoptions.formation import Formation -from game.utils import Heading, nautical_miles -from .ibuilder import IBuilder -from .loiter import LoiterFlightPlan, LoiterLayout -from .waypointbuilder import WaypointBuilder - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class SweepLayout(LoiterLayout): - nav_to: list[FlightWaypoint] - sweep_start: FlightWaypoint - sweep_end: FlightWaypoint - nav_from: list[FlightWaypoint] - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield self.hold - yield from self.nav_to - yield self.sweep_start - yield self.sweep_end - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class SweepFlightPlan(LoiterFlightPlan[SweepLayout]): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def combat_speed_waypoints(self) -> set[FlightWaypoint]: - return {self.layout.sweep_end} - - @property - def tot_waypoint(self) -> FlightWaypoint: - return self.layout.sweep_end - - def default_tot_offset(self) -> timedelta: - return -timedelta(minutes=5) - - @property - def sweep_start_time(self) -> datetime: - travel_time = self.total_time_between_waypoints( - self.layout.sweep_start, self.layout.sweep_end - ) - return self.sweep_end_time - travel_time - - @property - def sweep_end_time(self) -> datetime: - return self.tot - - def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.sweep_start: - return self.sweep_start_time - if waypoint == self.layout.sweep_end: - return self.sweep_end_time - return None - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.hold: - return self.push_time - return None - - @property - def push_time(self) -> datetime: - return self.sweep_end_time - self.travel_time_between_waypoints( - self.layout.hold, self.layout.sweep_end - ) - - @property - def mission_begin_on_station_time(self) -> datetime | None: - return None - - @property - def mission_departure_time(self) -> datetime: - return self.sweep_end_time - - def add_waypoint_actions(self) -> None: - super().add_waypoint_actions() - self.layout.sweep_start.set_option(Formation.LINE_ABREAST_OPEN) - self.layout.sweep_start.add_action( - EngageTargets( - nautical_miles(50), - [ - Targets.All.Air.Planes.Fighters, - Targets.All.Air.Planes.MultiroleFighters, - ], - ) - ) - - -class Builder(IBuilder[SweepFlightPlan, SweepLayout]): - def layout(self) -> SweepLayout: - assert self.package.waypoints is not None - target = self.package.target.position - heading = Heading.from_degrees( - self.package.waypoints.join.heading_between_point(target) - ) - start_pos = target.point_from_heading( - heading.degrees, -self.doctrine.sweep.distance.meters - ) - - builder = WaypointBuilder(self.flight, self.coalition) - start, end = builder.sweep(start_pos, target, self.doctrine.combat_altitude) - - hold = builder.hold(self._hold_point()) - - return SweepLayout( - departure=builder.takeoff(self.flight.departure), - hold=hold, - nav_to=builder.nav_path( - hold.position, start.position, self.doctrine.combat_altitude - ), - nav_from=builder.nav_path( - end.position, - self.flight.arrival.position, - self.doctrine.combat_altitude, - ), - sweep_start=start, - sweep_end=end, - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def _hold_point(self) -> Point: - assert self.package.waypoints is not None - origin = self.flight.departure.position - target = self.package.target.position - join = self.package.waypoints.join - ip = self.package.waypoints.ingress - return HoldZoneGeometry( - target, origin, ip, join, self.coalition, self.theater - ).find_best_hold_point() - - def build(self, dump_debug_info: bool = False) -> SweepFlightPlan: - return SweepFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/tarcap.py b/game/ato/flightplans/tarcap.py deleted file mode 100644 index 53fb546cb..000000000 --- a/game/ato/flightplans/tarcap.py +++ /dev/null @@ -1,126 +0,0 @@ -from __future__ import annotations - -import random -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime, timedelta -from typing import TYPE_CHECKING, Type - -from game.utils import Distance, Speed, feet -from .capbuilder import CapBuilder -from .patrolling import PatrollingFlightPlan, PatrollingLayout -from .waypointbuilder import WaypointBuilder - -if TYPE_CHECKING: - from ..flightwaypoint import FlightWaypoint - - -@dataclass(frozen=True) -class TarCapLayout(PatrollingLayout): - refuel: FlightWaypoint | None - - def iter_waypoints(self) -> Iterator[FlightWaypoint]: - yield self.departure - yield from self.nav_to - yield self.patrol_start - yield self.patrol_end - if self.refuel is not None: - yield self.refuel - yield from self.nav_from - yield self.arrival - if self.divert is not None: - yield self.divert - yield self.bullseye - - -class TarCapFlightPlan(PatrollingFlightPlan[TarCapLayout]): - @property - def patrol_duration(self) -> timedelta: - # Note that this duration only has an effect if there are no - # flights in the package that have requested escort. If the package - # requests an escort the CAP self.flight will remain on station for the - # duration of the escorted mission, or until it is winchester/bingo. - return self.flight.coalition.doctrine.cap.duration - - @property - def patrol_speed(self) -> Speed: - return self.flight.unit_type.preferred_patrol_speed( - self.layout.patrol_start.alt - ) - - @property - def engagement_distance(self) -> Distance: - return self.flight.coalition.doctrine.cap.engagement_range - - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def combat_speed_waypoints(self) -> set[FlightWaypoint]: - return {self.layout.patrol_start, self.layout.patrol_end} - - def default_tot_offset(self) -> timedelta: - return -timedelta(minutes=2) - - def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None: - if waypoint == self.layout.patrol_end: - return self.patrol_end_time - return super().depart_time_for_waypoint(waypoint) - - @property - def patrol_start_time(self) -> datetime: - start = self.package.escort_start_time - if start is not None: - return start + self.tot_offset - return self.tot - - @property - def patrol_end_time(self) -> datetime: - end = self.package.escort_end_time - if end is not None: - return end - return super().patrol_end_time - - -class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]): - def layout(self) -> TarCapLayout: - location = self.package.target - - preferred_alt = self.flight.unit_type.preferred_patrol_altitude - randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000) - patrol_alt = max( - self.doctrine.cap.min_patrol_altitude, - min(self.doctrine.cap.max_patrol_altitude, randomized_alt), - ) - - builder = WaypointBuilder(self.flight, self.coalition) - orbit0p, orbit1p = self.cap_racetrack_for_objective(location, barcap=False) - - start, end = builder.race_track(orbit0p, orbit1p, patrol_alt) - - refuel = None - nav_from_origin = orbit1p - - if self.package.waypoints is not None: - refuel = builder.refuel(self.package.waypoints.refuel) - nav_from_origin = refuel.position - - return TarCapLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, orbit0p, patrol_alt - ), - nav_from=builder.nav_path( - nav_from_origin, self.flight.arrival.position, patrol_alt - ), - patrol_start=start, - patrol_end=end, - refuel=refuel, - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> TarCapFlightPlan: - return TarCapFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/theaterrefueling.py b/game/ato/flightplans/theaterrefueling.py deleted file mode 100644 index d93eb4a8e..000000000 --- a/game/ato/flightplans/theaterrefueling.py +++ /dev/null @@ -1,83 +0,0 @@ -from __future__ import annotations - -from datetime import timedelta -from typing import Type - -from game.utils import Heading, feet, meters, nautical_miles -from .ibuilder import IBuilder -from .patrolling import PatrollingLayout -from .refuelingflightplan import RefuelingFlightPlan -from .waypointbuilder import WaypointBuilder - - -class TheaterRefuelingFlightPlan(RefuelingFlightPlan): - @staticmethod - def builder_type() -> Type[Builder]: - return Builder - - @property - def patrol_duration(self) -> timedelta: - return timedelta(hours=1) - - -class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]): - def layout(self) -> PatrollingLayout: - racetrack_half_distance = nautical_miles(20).meters - - location = self.package.target - - closest_boundary = self.threat_zones.closest_boundary(location.position) - heading_to_threat_boundary = Heading.from_degrees( - location.position.heading_between_point(closest_boundary) - ) - distance_to_threat = meters( - location.position.distance_to_point(closest_boundary) - ) - orbit_heading = heading_to_threat_boundary - - # Station 70nm outside the threat zone. - threat_buffer = nautical_miles(70) - if self.threat_zones.threatened(location.position): - orbit_distance = distance_to_threat + threat_buffer - else: - orbit_distance = distance_to_threat - threat_buffer - - racetrack_center = location.position.point_from_heading( - orbit_heading.degrees, orbit_distance.meters - ) - - racetrack_start = racetrack_center.point_from_heading( - orbit_heading.right.degrees, racetrack_half_distance - ) - - racetrack_end = racetrack_center.point_from_heading( - orbit_heading.left.degrees, racetrack_half_distance - ) - - builder = WaypointBuilder(self.flight, self.coalition) - - tanker_type = self.flight.unit_type - if tanker_type.patrol_altitude is not None: - altitude = tanker_type.patrol_altitude - else: - altitude = feet(21000) - - racetrack = builder.race_track(racetrack_start, racetrack_end, altitude) - - return PatrollingLayout( - departure=builder.takeoff(self.flight.departure), - nav_to=builder.nav_path( - self.flight.departure.position, racetrack_start, altitude - ), - nav_from=builder.nav_path( - racetrack_end, self.flight.arrival.position, altitude - ), - patrol_start=racetrack[0], - patrol_end=racetrack[1], - arrival=builder.land(self.flight.arrival), - divert=builder.divert(self.flight.divert), - bullseye=builder.bullseye(), - ) - - def build(self, dump_debug_info: bool = False) -> TheaterRefuelingFlightPlan: - return TheaterRefuelingFlightPlan(self.flight, self.layout()) diff --git a/game/ato/flightplans/uizonedisplay.py b/game/ato/flightplans/uizonedisplay.py deleted file mode 100644 index 8d880c878..000000000 --- a/game/ato/flightplans/uizonedisplay.py +++ /dev/null @@ -1,18 +0,0 @@ -import abc -from dataclasses import dataclass - -from dcs import Point - -from game.utils import Distance - - -@dataclass(frozen=True) -class UiZone: - points: list[Point] - radius: Distance - - -class UiZoneDisplay(abc.ABC): - @abc.abstractmethod - def ui_zone(self) -> UiZone: - ... diff --git a/game/ato/flightplans/waypointbuilder.py b/game/ato/flightplans/waypointbuilder.py deleted file mode 100644 index 37be083c7..000000000 --- a/game/ato/flightplans/waypointbuilder.py +++ /dev/null @@ -1,615 +0,0 @@ -from __future__ import annotations - -import random -from dataclasses import dataclass -from typing import ( - Iterable, - Iterator, - List, - Optional, - TYPE_CHECKING, - Tuple, - Union, -) - -from dcs.mapping import Point, Vector2 - -from game.ato.flightwaypoint import AltitudeReference, FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.theater import ( - ControlPoint, - MissionTarget, - OffMapSpawn, - TheaterGroundObject, - TheaterUnit, -) -from game.utils import Distance, feet, meters, nautical_miles - -if TYPE_CHECKING: - from game.coalition import Coalition - from game.transfers import MultiGroupTransport - from game.theater.theatergroup import TheaterGroup - from game.ato.flight import Flight - - -@dataclass(frozen=True) -class StrikeTarget: - name: str - target: Union[TheaterGroundObject, TheaterGroup, TheaterUnit, MultiGroupTransport] - - -class WaypointBuilder: - def __init__( - self, - flight: Flight, - coalition: Coalition, - targets: Optional[List[StrikeTarget]] = None, - ) -> None: - self.flight = flight - self.doctrine = coalition.doctrine - self.threat_zones = coalition.opponent.threat_zone - self.navmesh = coalition.nav_mesh - self.targets = targets - self._bullseye = coalition.bullseye - - @property - def is_helo(self) -> bool: - return self.flight.is_helo - - def takeoff(self, departure: ControlPoint) -> FlightWaypoint: - """Create takeoff waypoint for the given arrival airfield or carrier. - - Note that the takeoff waypoint will automatically be created by pydcs - when we create the group, but creating our own before generation makes - the planning code simpler. - - Args: - departure: Departure airfield or carrier. - """ - position = departure.position - if isinstance(departure, OffMapSpawn): - return FlightWaypoint( - "NAV", - FlightWaypointType.NAV, - position, - self.doctrine.resolve_rendezvous_altitude(self.is_helo), - description="Enter theater", - pretty_name="Enter theater", - ) - - return FlightWaypoint( - "TAKEOFF", - FlightWaypointType.TAKEOFF, - position, - meters(0), - alt_type="RADIO", - description="Takeoff", - pretty_name="Takeoff", - ) - - def land(self, arrival: ControlPoint) -> FlightWaypoint: - """Create descent waypoint for the given arrival airfield or carrier. - - Args: - arrival: Arrival airfield or carrier. - """ - position = arrival.position - if isinstance(arrival, OffMapSpawn): - return FlightWaypoint( - "NAV", - FlightWaypointType.NAV, - position, - self.doctrine.resolve_rendezvous_altitude(self.is_helo), - description="Exit theater", - pretty_name="Exit theater", - ) - - return FlightWaypoint( - "LANDING", - FlightWaypointType.LANDING_POINT, - position, - meters(0), - alt_type="RADIO", - description="Land", - pretty_name="Land", - control_point=arrival, - ) - - def divert(self, divert: Optional[ControlPoint]) -> Optional[FlightWaypoint]: - """Create divert waypoint for the given arrival airfield or carrier. - - Args: - divert: Divert airfield or carrier. - """ - if divert is None: - return None - - position = divert.position - altitude_type: AltitudeReference - if isinstance(divert, OffMapSpawn): - altitude = self.doctrine.resolve_rendezvous_altitude(self.is_helo) - altitude_type = "BARO" - else: - altitude = meters(0) - altitude_type = "RADIO" - - return FlightWaypoint( - "DIVERT", - FlightWaypointType.DIVERT, - position, - altitude, - alt_type=altitude_type, - description="Divert", - pretty_name="Divert", - only_for_player=True, - control_point=divert, - ) - - def bullseye(self) -> FlightWaypoint: - return FlightWaypoint( - "BULLSEYE", - FlightWaypointType.BULLSEYE, - self._bullseye.position, - meters(0), - description="Bullseye", - pretty_name="Bullseye", - only_for_player=True, - ) - - def hold(self, position: Point) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - return FlightWaypoint( - "HOLD", - FlightWaypointType.LOITER, - position, - self.doctrine.resolve_rendezvous_altitude(self.is_helo), - alt_type, - description="Wait until push time", - pretty_name="Hold", - ) - - def join(self, position: Point) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - return FlightWaypoint( - "JOIN", - FlightWaypointType.JOIN, - position, - self.doctrine.resolve_combat_altitude(self.is_helo), - alt_type, - description="Rendezvous with package", - pretty_name="Join", - ) - - def refuel(self, position: Point) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - return FlightWaypoint( - "REFUEL", - FlightWaypointType.REFUEL, - position, - self.doctrine.resolve_combat_altitude(self.is_helo), - alt_type, - description="Refuel from tanker", - pretty_name="Refuel", - ) - - def recovery_tanker(self, position: Point) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - - return FlightWaypoint( - "RECOVERY", - FlightWaypointType.RECOVERY_TANKER, - position, - feet(6000), - alt_type, - description="Recovery tanker for aircraft carriers", - pretty_name="Recovery", - ) - - def split(self, position: Point) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - return FlightWaypoint( - "SPLIT", - FlightWaypointType.SPLIT, - position, - self.doctrine.resolve_combat_altitude(self.is_helo), - alt_type, - description="Depart from package", - pretty_name="Split", - ) - - def ingress( - self, - ingress_type: FlightWaypointType, - position: Point, - objective: MissionTarget, - ) -> FlightWaypoint: - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - return FlightWaypoint( - "INGRESS", - ingress_type, - position, - self.doctrine.resolve_combat_altitude(self.is_helo), - alt_type, - description=f"INGRESS on {objective.name}", - pretty_name=f"INGRESS on {objective.name}", - targets=objective.strike_targets, - ) - - def bai_group(self, target: StrikeTarget) -> FlightWaypoint: - return self._target_point(target, f"ATTACK {target.name}") - - def dead_point(self, target: StrikeTarget) -> FlightWaypoint: - return self._target_point(target, f"STRIKE {target.name}") - - def sead_point(self, target: StrikeTarget) -> FlightWaypoint: - return self._target_point(target, f"STRIKE {target.name}") - - def strike_point(self, target: StrikeTarget) -> FlightWaypoint: - return self._target_point(target, f"STRIKE {target.name}") - - @staticmethod - def _target_point(target: StrikeTarget, description: str) -> FlightWaypoint: - return FlightWaypoint( - target.name, - FlightWaypointType.TARGET_POINT, - target.target.position, - meters(0), - "RADIO", - description=description, - pretty_name=description, - # The target waypoints are only for the player's benefit. AI tasks for - # the target are set on the ingress point so that they begin their attack - # *before* reaching the target. - only_for_player=True, - ) - - def strike_area(self, target: MissionTarget) -> FlightWaypoint: - return self._target_area(f"STRIKE {target.name}", target) - - def sead_area(self, target: MissionTarget) -> FlightWaypoint: - # Set flyover with ingress altitude to allow the flight to search and engage - # the target group at the ingress alt without suicide dive - return self._target_area( - f"SEAD on {target.name}", - target, - flyover=True, - altitude=self.doctrine.combat_altitude, - alt_type="BARO", - ) - - def dead_area(self, target: MissionTarget) -> FlightWaypoint: - return self._target_area(f"DEAD on {target.name}", target) - - def oca_strike_area(self, target: MissionTarget) -> FlightWaypoint: - return self._target_area(f"ATTACK {target.name}", target, flyover=True) - - def assault_area(self, target: MissionTarget) -> FlightWaypoint: - """A destination waypoint used by air-assault ground troops. - - This waypoint is an implementation detail for CTLD and should not be followed by - aircraft. - """ - # TODO: Add a property that can hide this waypoint from the player's flight - # plan. - return self._target_area(f"ASSAULT {target.name}", target) - - @staticmethod - def _target_area( - name: str, - location: MissionTarget, - flyover: bool = False, - altitude: Distance = meters(0), - alt_type: AltitudeReference = "RADIO", - ) -> FlightWaypoint: - waypoint = FlightWaypoint( - name, - FlightWaypointType.TARGET_GROUP_LOC, - location.position, - altitude, - alt_type, - description=name, - pretty_name=name, - ) - - # Most target waypoints are only for the player's benefit. AI tasks for - # the target are set on the ingress point so they begin their attack - # *before* reaching the target. - # - # The exception is for flight plans that require passing over the - # target. For example, OCA strikes need to get close enough to detect - # the targets in their engagement zone or they will RTB immediately. - if flyover: - waypoint.flyover = True - else: - waypoint.only_for_player = True - return waypoint - - @staticmethod - def race_track_start(position: Point, altitude: Distance) -> FlightWaypoint: - """Creates a racetrack start waypoint. - - Args: - position: Position of the waypoint. - altitude: Altitude of the racetrack. - """ - return FlightWaypoint( - "RACETRACK START", - FlightWaypointType.PATROL_TRACK, - position, - altitude, - description="Orbit between this point and the next point", - pretty_name="Race-track start", - ) - - @staticmethod - def race_track_end(position: Point, altitude: Distance) -> FlightWaypoint: - """Creates a racetrack end waypoint. - - Args: - position: Position of the waypoint. - altitude: Altitude of the racetrack. - """ - return FlightWaypoint( - "RACETRACK END", - FlightWaypointType.PATROL, - position, - altitude, - description="Orbit between this point and the previous point", - pretty_name="Race-track end", - ) - - def race_track( - self, start: Point, end: Point, altitude: Distance - ) -> Tuple[FlightWaypoint, FlightWaypoint]: - """Creates two waypoint for a racetrack orbit. - - Args: - start: The beginning racetrack waypoint. - end: The ending racetrack waypoint. - altitude: The racetrack altitude. - """ - return ( - self.race_track_start(start, altitude), - self.race_track_end(end, altitude), - ) - - @staticmethod - def orbit(start: Point, altitude: Distance) -> FlightWaypoint: - """Creates an circular orbit point. - - Args: - start: Position of the waypoint. - altitude: Altitude of the racetrack. - """ - - return FlightWaypoint( - "ORBIT", - FlightWaypointType.LOITER, - start, - altitude, - description="Anchor and hold at this point", - pretty_name="Orbit", - ) - - @staticmethod - def sweep_start(position: Point, altitude: Distance) -> FlightWaypoint: - """Creates a sweep start waypoint. - - Args: - position: Position of the waypoint. - altitude: Altitude of the sweep in meters. - """ - return FlightWaypoint( - "SWEEP START", - FlightWaypointType.INGRESS_SWEEP, - position, - altitude, - description="Proceed to the target and engage enemy aircraft", - pretty_name="Sweep start", - ) - - @staticmethod - def sweep_end(position: Point, altitude: Distance) -> FlightWaypoint: - """Creates a sweep end waypoint. - - Args: - position: Position of the waypoint. - altitude: Altitude of the sweep in meters. - """ - return FlightWaypoint( - "SWEEP END", - FlightWaypointType.EGRESS, - position, - altitude, - description="End of sweep", - pretty_name="Sweep end", - ) - - def sweep( - self, start: Point, end: Point, altitude: Distance - ) -> Tuple[FlightWaypoint, FlightWaypoint]: - """Creates two waypoint for a racetrack orbit. - - Args: - start: The beginning of the sweep. - end: The end of the sweep. - altitude: The sweep altitude. - """ - return self.sweep_start(start, altitude), self.sweep_end(end, altitude) - - def escort( - self, - ingress: Point, - target: MissionTarget, - ) -> Tuple[FlightWaypoint, FlightWaypoint]: - """Creates the waypoints needed to escort the package. - - Args: - ingress: The package ingress point. - target: The mission target. - """ - alt_type: AltitudeReference = "BARO" - if self.is_helo: - alt_type = "RADIO" - - # This would preferably be no points at all, and instead the Escort task - # would begin on the join point and end on the split point, however the - # escort task does not appear to work properly (see the longer - # description in gen.aircraft.JoinPointBuilder), so instead we give - # the escort flights a flight plan including the ingress point and target area. - ingress_wp = self.ingress(FlightWaypointType.INGRESS_ESCORT, ingress, target) - - return ingress_wp, FlightWaypoint( - "TARGET", - FlightWaypointType.TARGET_GROUP_LOC, - target.position, - self.doctrine.resolve_combat_altitude(self.is_helo), - alt_type, - description="Escort the package", - pretty_name="Target area", - ) - - @staticmethod - def pickup_zone(pick_up: MissionTarget) -> FlightWaypoint: - """Creates a pickup landing zone waypoint - This waypoint is used to generate the Trigger Zone used for AirAssault and - AirLift using the CTLD plugin (see LogisticsGenerator) - """ - return FlightWaypoint( - "PICKUPZONE", - FlightWaypointType.PICKUP_ZONE, - pick_up.position, - meters(0), - "RADIO", - description=f"Pick up cargo from {pick_up.name}", - pretty_name="Pick-up zone", - ) - - @staticmethod - def dropoff_zone(drop_off: MissionTarget) -> FlightWaypoint: - """Creates a dropoff landing zone waypoint - This waypoint is used to generate the Trigger Zone used for AirAssault and - AirLift using the CTLD plugin (see LogisticsGenerator) - """ - return FlightWaypoint( - "DROPOFFZONE", - FlightWaypointType.DROPOFF_ZONE, - drop_off.position, - meters(0), - "RADIO", - description=f"Drop off cargo at {drop_off.name}", - pretty_name="Drop-off zone", - ) - - @staticmethod - def cargo_stop(control_point: ControlPoint) -> FlightWaypoint: - """Creates a cargo stop waypoint. - This waypoint is used by AirLift as a landing and stopover waypoint - """ - return FlightWaypoint( - "CARGOSTOP", - FlightWaypointType.CARGO_STOP, - control_point.position, - meters(0), - "RADIO", - description=f"Stop for cargo at {control_point.name}", - pretty_name="Cargo stop", - control_point=control_point, - ) - - @staticmethod - def nav( - position: Point, altitude: Distance, altitude_is_agl: bool = False - ) -> FlightWaypoint: - """Creates a navigation point. - - Args: - position: Position of the waypoint. - altitude: Altitude of the waypoint. - altitude_is_agl: True for altitude is AGL. False if altitude is MSL. - """ - alt_type: AltitudeReference = "BARO" - if altitude_is_agl: - alt_type = "RADIO" - - return FlightWaypoint( - "NAV", - FlightWaypointType.NAV, - position, - altitude, - alt_type, - description="NAV", - pretty_name="Nav", - ) - - def nav_path( - self, a: Point, b: Point, altitude: Distance, altitude_is_agl: bool = False - ) -> List[FlightWaypoint]: - path = self.clean_nav_points(self.navmesh.shortest_path(a, b)) - return [self.nav(self.perturb(p), altitude, altitude_is_agl) for p in path] - - def clean_nav_points(self, points: Iterable[Point]) -> Iterator[Point]: - # Examine a sliding window of three waypoints. `current` is the waypoint - # being checked for prunability. `previous` is the last emitted waypoint - # before `current`. `nxt` is the waypoint after `current`. - previous: Optional[Point] = None - current: Optional[Point] = None - for nxt in points: - if current is None: - current = nxt - continue - if previous is None: - previous = current - current = nxt - continue - - if self.nav_point_prunable(previous, current, nxt): - current = nxt - continue - - yield current - previous = current - current = nxt - - def nav_point_prunable(self, previous: Point, current: Point, nxt: Point) -> bool: - previous_threatened = self.threat_zones.path_threatened(previous, current) - next_threatened = self.threat_zones.path_threatened(current, nxt) - pruned_threatened = self.threat_zones.path_threatened(previous, nxt) - previous_distance = meters(previous.distance_to_point(current)) - distance = meters(current.distance_to_point(nxt)) - distance_without = previous_distance + distance - if distance > distance_without: - # Don't prune paths to make them longer. - return False - - # We could shorten the path by removing the intermediate - # waypoint. Do so if the new path isn't higher threat. - if not pruned_threatened: - # The new path is not threatened, so safe to prune. - return True - - # The new path is threatened. Only allow if both paths were - # threatened anyway. - return previous_threatened and next_threatened - - @staticmethod - def perturb(point: Point) -> Point: - deviation = nautical_miles(1) - x_adj = random.randint(int(-deviation.meters), int(deviation.meters)) - y_adj = random.randint(int(-deviation.meters), int(deviation.meters)) - return point + Vector2(x_adj, y_adj) diff --git a/game/ato/flightroster.py b/game/ato/flightroster.py deleted file mode 100644 index a9ef5016a..000000000 --- a/game/ato/flightroster.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from typing import Optional, TYPE_CHECKING - -from game.ato.iflightroster import IFlightRoster - -if TYPE_CHECKING: - from game.squadrons import Squadron, Pilot - - -class FlightRoster(IFlightRoster): - def __init__(self, squadron: Squadron, initial_size: int = 0) -> None: - self.squadron = squadron - self.pilots: list[Optional[Pilot]] = [] - self.resize(initial_size) - - def iter_pilots(self) -> Iterator[Pilot | None]: - yield from self.pilots - - def pilot_at(self, idx: int) -> Pilot | None: - return self.pilots[idx] - - @property - def max_size(self) -> int: - return len(self.pilots) - - def resize(self, new_size: int) -> None: - if self.max_size > new_size: - self.squadron.return_pilots( - [p for p in self.pilots[new_size:] if p is not None] - ) - self.pilots = self.pilots[:new_size] - return - self.pilots.extend( - [ - self.squadron.claim_available_pilot() - for _ in range(new_size - self.max_size) - ] - ) - - def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None: - if pilot is not None: - self.squadron.claim_pilot(pilot) - if (current_pilot := self.pilots[index]) is not None: - self.squadron.return_pilot(current_pilot) - self.pilots[index] = pilot - - def clear(self) -> None: - self.squadron.return_pilots([p for p in self.pilots if p is not None]) diff --git a/game/ato/flightstate/__init__.py b/game/ato/flightstate/__init__.py deleted file mode 100644 index 3afe84f3a..000000000 --- a/game/ato/flightstate/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .completed import Completed -from .flightstate import FlightState -from .incombat import InCombat -from .inflight import InFlight -from .killed import Killed -from .navigating import Navigating -from .startup import StartUp -from .takeoff import Takeoff -from .taxi import Taxi -from .uninitialized import Uninitialized -from .waitingforstart import WaitingForStart diff --git a/game/ato/flightstate/actionstate.py b/game/ato/flightstate/actionstate.py deleted file mode 100644 index 323ab7092..000000000 --- a/game/ato/flightstate/actionstate.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from game.flightplan.waypointactions.waypointaction import WaypointAction - - -class ActionState: - def __init__(self, action: WaypointAction) -> None: - self.action = action - self._finished = False - - def describe(self) -> str: - return self.action.describe() - - def finish(self) -> None: - self._finished = True - - def is_finished(self) -> bool: - return self._finished - - def on_game_tick(self, time: datetime, duration: timedelta) -> timedelta: - return self.action.update_state(self, time, duration) diff --git a/game/ato/flightstate/atdeparture.py b/game/ato/flightstate/atdeparture.py deleted file mode 100644 index c51bfaaa1..000000000 --- a/game/ato/flightstate/atdeparture.py +++ /dev/null @@ -1,14 +0,0 @@ -from abc import ABC - -from dcs import Point - -from game.ato.flightstate import FlightState - - -class AtDeparture(FlightState, ABC): - @property - def cancelable(self) -> bool: - return True - - def estimate_position(self) -> Point: - return self.flight.departure.position diff --git a/game/ato/flightstate/completed.py b/game/ato/flightstate/completed.py deleted file mode 100644 index f09e20344..000000000 --- a/game/ato/flightstate/completed.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from .flightstate import FlightState -from ..starttype import StartType - -if TYPE_CHECKING: - from game.sim.gameupdateevents import GameUpdateEvents - - -class Completed(FlightState): - @property - def cancelable(self) -> bool: - return False - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - return - - @property - def is_waiting_for_start(self) -> bool: - return False - - def estimate_position(self) -> Point: - return self.flight.arrival.position - - @property - def spawn_type(self) -> StartType: - # TODO: May want to do something different to make these uncontrolled? - return StartType.COLD - - @property - def description(self) -> str: - return "Completed" diff --git a/game/ato/flightstate/flightstate.py b/game/ato/flightstate/flightstate.py deleted file mode 100644 index 46bf2f34b..000000000 --- a/game/ato/flightstate/flightstate.py +++ /dev/null @@ -1,123 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from datetime import datetime, timedelta -from typing import Optional, TYPE_CHECKING - -from dcs import Point - -from game.ato.starttype import StartType - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - from game.threatzones import ThreatPoly - - -class FlightState(ABC): - def __init__(self, flight: Flight, settings: Settings) -> None: - self.flight = flight - self.settings = settings - self.avoid_further_combat = False - - def reinitialize(self, now: datetime) -> None: - from game.ato.flightstate import WaitingForStart - - if self.flight.flight_plan.startup_time() <= now: - self._set_active_flight_state(now) - else: - self.flight.set_state(WaitingForStart(self.flight, self.settings)) - - def _set_active_flight_state(self, now: datetime) -> None: - from game.ato.flightstate import StartUp - from game.ato.flightstate import Taxi - from game.ato.flightstate import Takeoff - from game.ato.flightstate import Navigating - - match self.flight.start_type: - case StartType.COLD: - self.flight.set_state(StartUp(self.flight, self.settings, now)) - case StartType.WARM: - self.flight.set_state(Taxi(self.flight, self.settings, now)) - case StartType.RUNWAY: - self.flight.set_state(Takeoff(self.flight, self.settings, now)) - case StartType.IN_FLIGHT: - self.flight.set_state( - Navigating(self.flight, self.settings, waypoint_index=0) - ) - case _: - raise ValueError( - f"Unknown start type {self.flight.start_type} for {self.flight}" - ) - - @property - def alive(self) -> bool: - return True - - @property - @abstractmethod - def cancelable(self) -> bool: - ... - - @abstractmethod - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - ... - - @property - def in_flight(self) -> bool: - return False - - @property - def is_at_ip(self) -> bool: - return False - - @property - def in_combat(self) -> bool: - return False - - @property - def vulnerable_to_intercept(self) -> bool: - return False - - @property - def vulnerable_to_sam(self) -> bool: - return False - - @property - def will_join_air_combat(self) -> bool: - return False - - def should_halt_sim(self) -> bool: - return False - - @property - @abstractmethod - def is_waiting_for_start(self) -> bool: - ... - - @abstractmethod - def estimate_position(self) -> Point: - ... - - @property - @abstractmethod - def spawn_type(self) -> StartType: - ... - - def a2a_commit_region(self) -> Optional[ThreatPoly]: - return None - - def estimate_fuel(self) -> float: - """Returns the estimated remaining fuel **in kilograms**.""" - if (max_takeoff_fuel := self.flight.max_takeoff_fuel()) is not None: - return max_takeoff_fuel - return self.flight.unit_type.dcs_unit_type.fuel_max - - @property - @abstractmethod - def description(self) -> str: - """Describes the current flight state.""" - ... diff --git a/game/ato/flightstate/incombat.py b/game/ato/flightstate/incombat.py deleted file mode 100644 index ef3943314..000000000 --- a/game/ato/flightstate/incombat.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from game.utils import Distance, Speed -from .inflight import InFlight -from ..starttype import StartType - -if TYPE_CHECKING: - from game.sim.combat import FrozenCombat - from game.sim.gameupdateevents import GameUpdateEvents - - -class InCombat(InFlight): - def __init__(self, previous_state: InFlight, combat: FrozenCombat) -> None: - super().__init__( - previous_state.flight, - previous_state.settings, - previous_state.waypoint_index, - ) - self.previous_state = previous_state - self.combat = combat - - def exit_combat( - self, - events: GameUpdateEvents, - time: datetime, - elapsed_time: timedelta, - avoid_further_combat: bool = False, - ) -> None: - self.flight.set_state(self.previous_state) - self.previous_state.avoid_further_combat = avoid_further_combat - self.previous_state.on_game_tick(events, time, elapsed_time) - - @property - def in_combat(self) -> bool: - return True - - def estimate_position(self) -> Point: - return self.previous_state.estimate_position() - - def estimate_altitude(self) -> tuple[Distance, str]: - return self.previous_state.estimate_altitude() - - def estimate_speed(self) -> Speed: - return self.previous_state.estimate_speed() - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - # Combat ticking is handled elsewhere because combat objects may be shared - # across multiple flights. - pass - - @property - def is_at_ip(self) -> bool: - return False - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def vulnerable_to_intercept(self) -> bool: - # Interception results in the interceptor joining the existing combat rather - # than creating a new combat. - return False - - @property - def vulnerable_to_sam(self) -> bool: - # SAM contact results in the SAM joining the existing combat rather than - # creating a new combat. - return False - - @property - def spawn_type(self) -> StartType: - return StartType.IN_FLIGHT - - @property - def description(self) -> str: - return self.combat.describe() diff --git a/game/ato/flightstate/inflight.py b/game/ato/flightstate/inflight.py deleted file mode 100644 index fc0be5e3d..000000000 --- a/game/ato/flightstate/inflight.py +++ /dev/null @@ -1,169 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections import deque -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from game.ato.flightstate import Completed -from game.ato.flightstate.actionstate import ActionState -from game.ato.flightstate.flightstate import FlightState -from game.ato.flightwaypoint import FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.ato.starttype import StartType -from game.utils import Distance, LBS_TO_KG, Speed, pairwise - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - - -class InFlight(FlightState, ABC): - def __init__( - self, - flight: Flight, - settings: Settings, - waypoint_index: int, - has_aborted: bool = False, - ) -> None: - super().__init__(flight, settings) - waypoints = self.flight.flight_plan.waypoints - self.waypoint_index = waypoint_index - self.has_aborted = has_aborted - self.current_waypoint = waypoints[self.waypoint_index] - # TODO: Error checking for flight plans without landing waypoints. - self.next_waypoint = waypoints[self.waypoint_index + 1] - self.total_time_to_next_waypoint = self.travel_time_between_waypoints() - self.elapsed_time = timedelta() - self.current_waypoint_elapsed = False - self.pending_actions: deque[ActionState] = deque( - ActionState(a) for a in self.current_waypoint.actions - ) - - @property - def current_action(self) -> ActionState | None: - if self.pending_actions: - return self.pending_actions[0] - return None - - @property - def cancelable(self) -> bool: - return False - - @property - def in_flight(self) -> bool: - return True - - def has_passed_waypoint(self, waypoint: FlightWaypoint) -> bool: - index = self.flight.flight_plan.waypoints.index(waypoint) - return index <= self.waypoint_index - - def travel_time_between_waypoints(self) -> timedelta: - return self.flight.flight_plan.travel_time_between_waypoints( - self.current_waypoint, self.next_waypoint - ) - - @abstractmethod - def estimate_position(self) -> Point: - ... - - @abstractmethod - def estimate_altitude(self) -> tuple[Distance, str]: - ... - - @abstractmethod - def estimate_speed(self) -> Speed: - ... - - def estimate_fuel_at_current_waypoint(self) -> float: - initial_fuel = super().estimate_fuel() - if self.flight.unit_type.fuel_consumption is None: - return initial_fuel - initial_fuel -= self.flight.unit_type.fuel_consumption.taxi * LBS_TO_KG - waypoints = self.flight.flight_plan.waypoints[: self.waypoint_index + 1] - for a, b in pairwise(waypoints[:-1]): - consumption = self.flight.flight_plan.fuel_consumption_between_points(a, b) - assert consumption is not None - initial_fuel -= consumption * LBS_TO_KG - return initial_fuel - - def next_waypoint_state(self) -> FlightState: - from .racetrack import RaceTrack - from .navigating import Navigating - - new_index = self.waypoint_index + 1 - if self.next_waypoint.waypoint_type is FlightWaypointType.LANDING_POINT: - return Completed(self.flight, self.settings) - if self.next_waypoint.waypoint_type is FlightWaypointType.PATROL_TRACK: - return RaceTrack(self.flight, self.settings, new_index) - return Navigating(self.flight, self.settings, new_index) - - def advance_to_next_waypoint(self) -> FlightState: - new_state = self.next_waypoint_state() - self.flight.set_state(new_state) - self.current_waypoint_elapsed = True - return new_state - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - while (action := self.current_action) is not None: - duration = action.on_game_tick(time, duration) - if action.is_finished(): - self.pending_actions.popleft() - if duration <= timedelta(): - return - - self.elapsed_time += duration - if self.elapsed_time > self.total_time_to_next_waypoint: - new_state = self.advance_to_next_waypoint() - - # Roll over any extra time to the next state. We don't need to loop here - # even if we've passed more than one waypoint because the new state will do - # the same. There is a small gap here where we only do that for other *in - # flight* states. We don't need to tick combat states (combat is ticked - # separately) or completed states at all, so the only states that might be - # under-ticked are the pre-takeoff states, where it's not really that - # critical if we under-simulate them by the tick period or less. The tick - # period at time of writing is one second. Not enough to throw off ground - # ops, but at 600 knots we'd be getting the position wrong by up to 1000 - # feet. - rollover = self.elapsed_time - self.total_time_to_next_waypoint - new_state.on_game_tick(events, time, rollover) - - @property - def is_at_ip(self) -> bool: - contact_types = { - FlightWaypointType.INGRESS_BAI, - FlightWaypointType.INGRESS_CAS, - FlightWaypointType.INGRESS_DEAD, - FlightWaypointType.INGRESS_OCA_AIRCRAFT, - FlightWaypointType.INGRESS_OCA_RUNWAY, - FlightWaypointType.INGRESS_SEAD, - FlightWaypointType.INGRESS_STRIKE, - FlightWaypointType.INGRESS_AIR_ASSAULT, - } - return self.current_waypoint.waypoint_type in contact_types - - @property - def vulnerable_to_intercept(self) -> bool: - return True - - @property - def vulnerable_to_sam(self) -> bool: - return True - - @property - def will_join_air_combat(self) -> bool: - return self.flight.flight_type.is_air_to_air - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def spawn_type(self) -> StartType: - return StartType.IN_FLIGHT diff --git a/game/ato/flightstate/killed.py b/game/ato/flightstate/killed.py deleted file mode 100644 index 86046a402..000000000 --- a/game/ato/flightstate/killed.py +++ /dev/null @@ -1,50 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from game.settings import Settings -from .flightstate import FlightState -from ..starttype import StartType - -if TYPE_CHECKING: - from .. import Flight - from game.sim.gameupdateevents import GameUpdateEvents - - -class Killed(FlightState): - def __init__( - self, last_position: Point, flight: Flight, settings: Settings - ) -> None: - super().__init__(flight, settings) - self.last_position = last_position - - @property - def cancelable(self) -> bool: - return False - - @property - def alive(self) -> bool: - return False - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - return - - @property - def is_waiting_for_start(self) -> bool: - return False - - def estimate_position(self) -> Point: - return self.last_position - - @property - def spawn_type(self) -> StartType: - raise RuntimeError("Attempted to spawn a dead flight") - - @property - def description(self) -> str: - return "KIA" diff --git a/game/ato/flightstate/navigating.py b/game/ato/flightstate/navigating.py deleted file mode 100644 index dbaf67a58..000000000 --- a/game/ato/flightstate/navigating.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from game.ato.flightstate import InFlight -from game.ato.starttype import StartType -from game.utils import Distance, LBS_TO_KG, Speed, meters - -if TYPE_CHECKING: - from game.sim.gameupdateevents import GameUpdateEvents - - -def lerp(v0: float, v1: float, t: float) -> float: - return (1 - t) * v0 + t * v1 - - -class Navigating(InFlight): - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - super().on_game_tick(events, time, duration) - - # If the parent tick caused this waypoint to become inactive don't update the - # position based on our now invalid state. - if not self.current_waypoint_elapsed: - events.update_flight_position(self.flight, self.estimate_position()) - - def progress(self) -> float: - # if next waypoint is very close, assume we reach it immediately to avoid divide - # by zero error - if self.total_time_to_next_waypoint.total_seconds() < 1: - return 1.0 - - return ( - self.elapsed_time.total_seconds() - / self.total_time_to_next_waypoint.total_seconds() - ) - - def estimate_position(self) -> Point: - return self.current_waypoint.position.lerp( - self.next_waypoint.position, self.progress() - ) - - def estimate_altitude(self) -> tuple[Distance, str]: - # This does not behave well when one of the waypoints is AGL and the other is - # MSL. We can't really avoid that problem though. We don't know where the ground - # is, so conversions between them are impossible, and we do need to use AGL - # altitudes for takeoff and landing waypoints (even if we had the runway - # elevation, we don't have elevation for FARPs). - return ( - meters( - lerp( - self.current_waypoint.alt.meters, - self.next_waypoint.alt.meters, - self.progress(), - ) - ), - self.current_waypoint.alt_type, - ) - - def estimate_speed(self) -> Speed: - return self.flight.flight_plan.speed_between_waypoints( - self.current_waypoint, self.next_waypoint - ) - - def estimate_fuel(self) -> float: - initial_fuel = self.estimate_fuel_at_current_waypoint() - ppm = self.flight.flight_plan.fuel_rate_to_between_points( - self.current_waypoint, self.next_waypoint - ) - if ppm is None: - return initial_fuel - position = self.estimate_position() - distance = meters(self.current_waypoint.position.distance_to_point(position)) - consumption = distance.nautical_miles * ppm * LBS_TO_KG - return initial_fuel - consumption - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def spawn_type(self) -> StartType: - return StartType.IN_FLIGHT - - @property - def description(self) -> str: - if (action := self.current_action) is not None: - return action.describe() - - if self.has_aborted: - abort = "(Aborted) " - else: - abort = "" - return f"{abort}Flying to {self.next_waypoint.name}" diff --git a/game/ato/flightstate/racetrack.py b/game/ato/flightstate/racetrack.py deleted file mode 100644 index 14bcd86c4..000000000 --- a/game/ato/flightstate/racetrack.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations - -from datetime import timedelta -from typing import Optional, TYPE_CHECKING - -from dcs import Point -from shapely.geometry import LineString - -from game.ato import FlightType -from game.ato.flightstate import InFlight -from game.threatzones import ThreatPoly -from game.utils import Distance, Speed, dcs_to_shapely_point - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - - -class RaceTrack(InFlight): - def __init__(self, flight: Flight, settings: Settings, waypoint_index: int) -> None: - assert flight.flight_plan.is_patrol(flight.flight_plan) - self.patrol_duration = flight.flight_plan.patrol_duration - super().__init__(flight, settings, waypoint_index) - self.commit_region = LineString( - [ - dcs_to_shapely_point(self.current_waypoint.position), - dcs_to_shapely_point(self.next_waypoint.position), - ] - ).buffer(flight.flight_plan.engagement_distance.meters) - - def estimate_position(self) -> Point: - # Prevent spawning racetracks in the middle of a leg. For simplicity we - # always start the aircraft at the beginning of the racetrack. - return self.current_waypoint.position - - def estimate_altitude(self) -> tuple[Distance, str]: - return self.current_waypoint.alt, self.current_waypoint.alt_type - - def estimate_speed(self) -> Speed: - return self.flight.unit_type.preferred_patrol_speed(self.estimate_altitude()[0]) - - def estimate_fuel(self) -> float: - # TODO: Estimate loiter consumption per minute? - return self.estimate_fuel_at_current_waypoint() - - def travel_time_between_waypoints(self) -> timedelta: - return self.patrol_duration - - def a2a_commit_region(self) -> Optional[ThreatPoly]: - if self.flight.flight_type in {FlightType.BARCAP, FlightType.TARCAP}: - return self.commit_region - return None - - @property - def description(self) -> str: - return f"Patrolling for {self.patrol_duration - self.elapsed_time}" diff --git a/game/ato/flightstate/startup.py b/game/ato/flightstate/startup.py deleted file mode 100644 index f9f7c25d5..000000000 --- a/game/ato/flightstate/startup.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from .atdeparture import AtDeparture -from .taxi import Taxi -from ..starttype import StartType - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - - -class StartUp(AtDeparture): - def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None: - super().__init__(flight, settings) - self.completion_time = now + flight.flight_plan.estimate_startup() - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - if time < self.completion_time: - return - self.flight.set_state(Taxi(self.flight, self.settings, time)) - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def spawn_type(self) -> StartType: - return StartType.COLD - - def should_halt_sim(self) -> bool: - if ( - self.flight.client_count > 0 - and self.settings.player_mission_interrupts_sim_at is StartType.COLD - ): - logging.info( - f"Interrupting simulation because {self.flight} has players and has " - "reached startup time" - ) - return True - return False - - @property - def description(self) -> str: - return "Starting up" diff --git a/game/ato/flightstate/takeoff.py b/game/ato/flightstate/takeoff.py deleted file mode 100644 index 119f0d993..000000000 --- a/game/ato/flightstate/takeoff.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from .atdeparture import AtDeparture -from .navigating import Navigating -from ..starttype import StartType -from ...utils import LBS_TO_KG - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - - -class Takeoff(AtDeparture): - def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None: - super().__init__(flight, settings) - # TODO: Not accounted for in FlightPlan, can cause discrepancy without loiter. - self.completion_time = now + timedelta(seconds=30) - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - if time < self.completion_time: - return - self.flight.set_state(Navigating(self.flight, self.settings, waypoint_index=0)) - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def spawn_type(self) -> StartType: - return StartType.RUNWAY - - def estimate_fuel(self) -> float: - initial_fuel = super().estimate_fuel() - if self.flight.unit_type.fuel_consumption is None: - return initial_fuel - return initial_fuel - self.flight.unit_type.fuel_consumption.taxi * LBS_TO_KG - - def should_halt_sim(self) -> bool: - if ( - self.flight.client_count > 0 - and self.settings.player_mission_interrupts_sim_at is StartType.RUNWAY - ): - logging.info( - f"Interrupting simulation because {self.flight} has players and has " - "reached takeoff time" - ) - return True - return False - - @property - def description(self) -> str: - return "Taking off" diff --git a/game/ato/flightstate/taxi.py b/game/ato/flightstate/taxi.py deleted file mode 100644 index 96f7a430e..000000000 --- a/game/ato/flightstate/taxi.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from .atdeparture import AtDeparture -from .takeoff import Takeoff -from ..starttype import StartType - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - - -class Taxi(AtDeparture): - def __init__(self, flight: Flight, settings: Settings, now: datetime) -> None: - super().__init__(flight, settings) - self.completion_time = now + flight.flight_plan.estimate_ground_ops() - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - if time < self.completion_time: - return - self.flight.set_state(Takeoff(self.flight, self.settings, time)) - - @property - def is_waiting_for_start(self) -> bool: - return False - - @property - def spawn_type(self) -> StartType: - return StartType.WARM - - def should_halt_sim(self) -> bool: - if ( - self.flight.client_count > 0 - and self.settings.player_mission_interrupts_sim_at is StartType.WARM - ): - logging.info( - f"Interrupting simulation because {self.flight} has players and has " - "reached taxi time" - ) - return True - return False - - @property - def description(self) -> str: - return "Taxiing" diff --git a/game/ato/flightstate/uninitialized.py b/game/ato/flightstate/uninitialized.py deleted file mode 100644 index e3f0b09a6..000000000 --- a/game/ato/flightstate/uninitialized.py +++ /dev/null @@ -1,49 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs import Point - -from .flightstate import FlightState -from ..starttype import StartType - -if TYPE_CHECKING: - from game.sim.gameupdateevents import GameUpdateEvents - - -class Uninitialized(FlightState): - @property - def cancelable(self) -> bool: - return True - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - self.reinitialize(time) - self.flight.state.on_game_tick(events, time, duration) - - @property - def is_waiting_for_start(self) -> bool: - return True - - def estimate_position(self) -> Point: - raise RuntimeError("Attempted to simulate flight that is not fully initialized") - - @property - def spawn_type(self) -> StartType: - raise RuntimeError("Attempted to simulate flight that is not fully initialized") - - @property - def description(self) -> str: - if self.flight.start_type is StartType.COLD: - action = "Starting up" - elif self.flight.start_type is StartType.WARM: - action = "Taxiing" - elif self.flight.start_type is StartType.RUNWAY: - action = "Taking off" - elif self.flight.start_type is StartType.IN_FLIGHT: - action = "In flight" - else: - raise ValueError(f"Unhandled StartType: {self.flight.start_type}") - return f"{action} at {self.flight.flight_plan.startup_time():%H:%M:%S}" diff --git a/game/ato/flightstate/waitingforstart.py b/game/ato/flightstate/waitingforstart.py deleted file mode 100644 index 9e65235db..000000000 --- a/game/ato/flightstate/waitingforstart.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from game.ato.starttype import StartType -from .atdeparture import AtDeparture -from .flightstate import FlightState -from .navigating import Navigating -from .startup import StartUp -from .takeoff import Takeoff -from .taxi import Taxi - -if TYPE_CHECKING: - from game.ato.flight import Flight - from game.settings import Settings - from game.sim.gameupdateevents import GameUpdateEvents - - -class WaitingForStart(AtDeparture): - def __init__(self, flight: Flight, settings: Settings) -> None: - super().__init__(flight, settings) - - @property - def start_type(self) -> StartType: - return self.flight.start_type - - @property - def start_time(self) -> datetime: - return self.flight.flight_plan.startup_time() - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - if time < self.start_time: - return - - new_state: FlightState - if self.start_type is StartType.COLD: - new_state = StartUp(self.flight, self.settings, time) - elif self.start_type is StartType.WARM: - new_state = Taxi(self.flight, self.settings, time) - elif self.start_type is StartType.RUNWAY: - new_state = Takeoff(self.flight, self.settings, time) - else: - new_state = Navigating(self.flight, self.settings, waypoint_index=0) - self.flight.set_state(new_state) - - @property - def is_waiting_for_start(self) -> bool: - return True - - def time_remaining(self, time: datetime) -> timedelta: - return self.start_time - time - - @property - def spawn_type(self) -> StartType: - return self.flight.start_type - - @property - def description(self) -> str: - if self.start_type is StartType.COLD: - start_type = "startup" - elif self.start_type is StartType.WARM: - start_type = "taxi" - elif self.start_type is StartType.RUNWAY: - start_type = "takeoff" - elif self.start_type is StartType.IN_FLIGHT: - start_type = "air start" - else: - raise ValueError(f"Unhandled StartType: {self.start_type}") - return f"Waiting for {start_type} at {self.start_time:%H:%M:%S}" diff --git a/game/ato/flighttype.py b/game/ato/flighttype.py deleted file mode 100644 index 18216ea35..000000000 --- a/game/ato/flighttype.py +++ /dev/null @@ -1,118 +0,0 @@ -from __future__ import annotations - -from enum import Enum - -from game.sidc import AirEntity - - -class FlightType(Enum): - """Enumeration of mission types. - - The value of each enumeration is the name that will be shown in the UI. - - These values are persisted to the save game as well since they are a part of - each flight and thus a part of the ATO, so changing these values will break - save compat. - - When adding new mission types to this list, you will also need to update: - - * flightplan.py: Add waypoint population in generate_flight_plan. Add a new flight - plan type if necessary, though most are a subclass of StrikeFlightPlan. - * aircraftgenerator.py: Add a configuration method and call it in setup_flight_group. This is - responsible for configuring waypoint 0 actions like setting ROE, threat reaction, - and mission abort parameters (winchester, bingo, etc). - * Implementations of MissionTarget.mission_types: A mission type can only be planned - against compatible targets. The mission_types method of each target class defines - which missions may target it. - * resources/units/aircraft/*.yaml: Assign aircraft weight for the new task type in - the `tasks` dict for all capable aircraft. - - You may also need to update: - - * flightwaypointtype.py: Add a new waypoint type if necessary. Most mission types - will need these, as aircraftgenerator.py uses the ingress point type to specialize AI - tasks, and non-strike-like missions will need more specialized control. - * ai_flight_planner.py: Use the new mission type in propose_missions so the AI will - plan the new mission type. - * FlightType.is_air_to_air and FlightType.is_air_to_ground: If the new mission type - fits either of these categories, update those methods accordingly. - """ - - TARCAP = "TARCAP" - BARCAP = "BARCAP" - CAS = "CAS" - INTERCEPTION = "Intercept" - STRIKE = "Strike" - ANTISHIP = "Anti-ship" - SEAD = "SEAD" - DEAD = "DEAD" - ESCORT = "Escort" - BAI = "BAI" - SWEEP = "Fighter sweep" - OCA_RUNWAY = "OCA/Runway" - OCA_AIRCRAFT = "OCA/Aircraft" - AEWC = "AEW&C" - TRANSPORT = "Transport" - SEAD_ESCORT = "SEAD Escort" - REFUELING = "Refueling" - FERRY = "Ferry" - AIR_ASSAULT = "Air Assault" - - def __str__(self) -> str: - return self.value - - @classmethod - def from_name(cls, name: str) -> FlightType: - for entry in cls: - if name == entry.value: - return entry - raise KeyError(f"No FlightType with name {name}") - - @property - def is_air_to_air(self) -> bool: - return self in { - FlightType.TARCAP, - FlightType.BARCAP, - FlightType.INTERCEPTION, - FlightType.ESCORT, - FlightType.SWEEP, - } - - @property - def is_air_to_ground(self) -> bool: - return self in { - FlightType.CAS, - FlightType.STRIKE, - FlightType.ANTISHIP, - FlightType.SEAD, - FlightType.DEAD, - FlightType.BAI, - FlightType.OCA_RUNWAY, - FlightType.OCA_AIRCRAFT, - FlightType.SEAD_ESCORT, - FlightType.AIR_ASSAULT, - } - - @property - def entity_type(self) -> AirEntity: - return { - FlightType.AEWC: AirEntity.AIRBORNE_EARLY_WARNING, - FlightType.ANTISHIP: AirEntity.ANTISURFACE_WARFARE, - FlightType.BAI: AirEntity.ATTACK_STRIKE, - FlightType.BARCAP: AirEntity.FIGHTER, - FlightType.CAS: AirEntity.ATTACK_STRIKE, - FlightType.DEAD: AirEntity.ATTACK_STRIKE, - FlightType.ESCORT: AirEntity.ESCORT, - FlightType.FERRY: AirEntity.UNSPECIFIED, - FlightType.INTERCEPTION: AirEntity.FIGHTER, - FlightType.OCA_AIRCRAFT: AirEntity.ATTACK_STRIKE, - FlightType.OCA_RUNWAY: AirEntity.ATTACK_STRIKE, - FlightType.REFUELING: AirEntity.TANKER, - FlightType.SEAD: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE, - FlightType.SEAD_ESCORT: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE, - FlightType.STRIKE: AirEntity.ATTACK_STRIKE, - FlightType.SWEEP: AirEntity.FIGHTER, - FlightType.TARCAP: AirEntity.FIGHTER, - FlightType.TRANSPORT: AirEntity.UTILITY, - FlightType.AIR_ASSAULT: AirEntity.ROTARY_WING, - }.get(self, AirEntity.UNSPECIFIED) diff --git a/game/ato/flightwaypoint.py b/game/ato/flightwaypoint.py deleted file mode 100644 index 590d0745f..000000000 --- a/game/ato/flightwaypoint.py +++ /dev/null @@ -1,71 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from datetime import datetime -from typing import Literal, TYPE_CHECKING - -from dcs import Point - -from game.ato.flightwaypointtype import FlightWaypointType -from game.flightplan.waypointactions.waypointaction import WaypointAction -from game.flightplan.waypointoptions.waypointoption import WaypointOption -from game.theater.theatergroup import TheaterUnit -from game.utils import Distance, meters - -if TYPE_CHECKING: - from game.theater import ControlPoint - -AltitudeReference = Literal["BARO", "RADIO"] - - -@dataclass -class FlightWaypoint: - name: str - waypoint_type: FlightWaypointType - position: Point - alt: Distance = meters(0) - alt_type: AltitudeReference = "BARO" - control_point: ControlPoint | None = None - - # TODO: Merge with pretty_name. - # Only used in the waypoint list in the flight edit page. No sense - # having three names. A short and long form is enough. - description: str = "" - - targets: list[TheaterUnit] = field(default_factory=list) - obj_name: str = "" - pretty_name: str = "" - only_for_player: bool = False - flyover: bool = False - - # The minimum amount of fuel remaining at this waypoint in pounds. - min_fuel: float | None = None - - wants_escort: bool = False - - actions: list[WaypointAction] = field(default_factory=list) - options: dict[str, WaypointOption] = field(default_factory=dict) - - # These are set very late by the air conflict generator (part of mission - # generation). We do it late so that we don't need to propagate changes - # to waypoint times whenever the player alters the package TOT or the - # flight's offset in the UI. - tot: datetime | None = None - departure_time: datetime | None = None - - def add_action(self, action: WaypointAction) -> None: - self.actions.append(action) - - def set_option(self, option: WaypointOption) -> None: - self.options[option.id()] = option - - @property - def x(self) -> float: - return self.position.x - - @property - def y(self) -> float: - return self.position.y - - def __hash__(self) -> int: - return hash(id(self)) diff --git a/game/ato/flightwaypointtype.py b/game/ato/flightwaypointtype.py deleted file mode 100644 index ab79fd5c0..000000000 --- a/game/ato/flightwaypointtype.py +++ /dev/null @@ -1,53 +0,0 @@ -from enum import IntEnum, unique - - -@unique -class FlightWaypointType(IntEnum): - """Enumeration of waypoint types. - - The value of the enum has no meaning but should remain stable to prevent breaking - save game compatibility. - - When adding a new waypoint type, you will also need to update: - - * waypointbuilder.py: Add a builder to simplify construction of the new waypoint - type unless the new waypoint type will be a parameter to an existing builder - method (such as how escort ingress waypoints work). - * aircraftgenerator.py: Associate AI actions with the new waypoint type by subclassing - PydcsWaypointBuilder and using it in PydcsWaypointBuilder.for_waypoint. - """ - - TAKEOFF = 0 # Take off point - ASCEND_POINT = 1 # Ascension point after take off - PATROL = 2 # Patrol point - PATROL_TRACK = 3 # Patrol race track - NAV = 4 # Nav point - INGRESS_STRIKE = 5 # Ingress strike (For generator, means that this should have bombing on next TARGET_POINT points) - INGRESS_SEAD = 6 # Ingress sead (For generator, means that this should attack groups on TARGET_GROUP_LOC points) - INGRESS_CAS = 7 # Ingress cas (should start CAS task) - CAS = 8 # Unused. - EGRESS = 9 # Should stop attack - DESCENT_POINT = 10 # Should start descending to pattern alt - LANDING_POINT = 11 # Should land there - TARGET_POINT = 12 # A target building or static object, position - TARGET_GROUP_LOC = 13 # A target group approximate location - TARGET_SHIP = 14 # Unused. - CUSTOM = 15 # User waypoint (no specific behaviour) - JOIN = 16 - SPLIT = 17 - LOITER = 18 - INGRESS_ESCORT = 19 - INGRESS_DEAD = 20 - INGRESS_SWEEP = 21 - INGRESS_BAI = 22 - DIVERT = 23 - INGRESS_OCA_RUNWAY = 24 - INGRESS_OCA_AIRCRAFT = 25 - PICKUP_ZONE = 26 # Pickup Zone for cargo or troops - DROPOFF_ZONE = 27 # Dropoff Zone for cargo or troops - BULLSEYE = 28 - REFUEL = 29 # Should look for nearby tanker to refuel from. - CARGO_STOP = 30 # Stopover landing point using the LandingReFuAr waypoint type - INGRESS_AIR_ASSAULT = 31 - RECOVERY_TANKER = 32 - INGRESS_ANTI_SHIP = 33 diff --git a/game/ato/iflightroster.py b/game/ato/iflightroster.py deleted file mode 100644 index 32231445c..000000000 --- a/game/ato/iflightroster.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Optional, TYPE_CHECKING, Iterator - -if TYPE_CHECKING: - from game.squadrons import Pilot - - -class IFlightRoster(ABC): - @abstractmethod - def iter_pilots(self) -> Iterator[Pilot | None]: - ... - - @abstractmethod - def pilot_at(self, idx: int) -> Pilot | None: - ... - - @property - @abstractmethod - def max_size(self) -> int: - ... - - @abstractmethod - def resize(self, new_size: int) -> None: - ... - - @abstractmethod - def set_pilot(self, index: int, pilot: Optional[Pilot]) -> None: - ... - - @abstractmethod - def clear(self) -> None: - ... diff --git a/game/ato/loadouts.py b/game/ato/loadouts.py deleted file mode 100644 index 158afbf22..000000000 --- a/game/ato/loadouts.py +++ /dev/null @@ -1,265 +0,0 @@ -from __future__ import annotations - -import copy -import datetime -import logging -from collections.abc import Iterable -from typing import Iterator, Mapping, Optional, TYPE_CHECKING, Type, Any - -from dcs.unittype import FlyingType - -from game.data.weapons import Pylon, Weapon, WeaponType -from game.dcs.aircrafttype import AircraftType -from .flighttype import FlightType - -if TYPE_CHECKING: - from .flight import Flight - - -class Loadout: - def __init__( - self, - name: str, - pylons: Mapping[int, Optional[Weapon]], - date: Optional[datetime.date], - is_custom: bool = False, - ) -> None: - self.name = name - # We clear unused pylon entries on initialization, but UI actions can still - # cause a pylon to be emptied, so make the optional type explicit. - self.pylons: Mapping[int, Optional[Weapon]] = { - k: v for k, v in pylons.items() if v is not None - } - self.date = date - self.is_custom = is_custom - - def derive_custom(self, name: str) -> Loadout: - return Loadout(name, self.pylons, self.date, is_custom=True) - - def clone(self) -> Loadout: - return Loadout( - self.name, dict(self.pylons), copy.deepcopy(self.date), self.is_custom - ) - - def has_weapon_of_type(self, weapon_type: WeaponType) -> bool: - for weapon in self.pylons.values(): - if weapon is not None and weapon.weapon_group.type is weapon_type: - return True - return False - - @staticmethod - def _fallback_for( - weapon: Weapon, - pylon: Pylon, - date: datetime.date, - skip_types: Optional[Iterable[WeaponType]] = None, - ) -> Optional[Weapon]: - if skip_types is None: - skip_types = set() - for fallback in weapon.fallbacks: - if not pylon.can_equip(fallback): - continue - if not fallback.available_on(date): - continue - if fallback.weapon_group.type in skip_types: - continue - return fallback - return None - - def degrade_for_date(self, unit_type: AircraftType, date: datetime.date) -> Loadout: - if self.date is not None and self.date <= date: - return Loadout(self.name, self.pylons, self.date, self.is_custom) - - new_pylons = dict(self.pylons) - for pylon_number, weapon in self.pylons.items(): - if weapon is None: - del new_pylons[pylon_number] - continue - if not weapon.available_on(date): - pylon = Pylon.for_aircraft(unit_type, pylon_number) - fallback = self._fallback_for(weapon, pylon, date) - if fallback is None: - del new_pylons[pylon_number] - else: - new_pylons[pylon_number] = fallback - loadout = Loadout(self.name, new_pylons, date, self.is_custom) - # If this is not a custom loadout, we should replace any LGBs with iron bombs if - # the loadout lost its TGP. - # - # If the loadout was chosen explicitly by the user, assume they know what - # they're doing. They may be coordinating buddy-lase. - if not loadout.is_custom: - loadout.replace_lgbs_if_no_tgp(unit_type, date) - return loadout - - def replace_lgbs_if_no_tgp( - self, unit_type: AircraftType, date: datetime.date - ) -> None: - if self.has_weapon_of_type(WeaponType.TGP): - return - - if unit_type.has_built_in_target_pod: - return - - new_pylons = dict(self.pylons) - for pylon_number, weapon in self.pylons.items(): - if weapon is not None and weapon.weapon_group.type is WeaponType.LGB: - pylon = Pylon.for_aircraft(unit_type, pylon_number) - fallback = self._fallback_for( - weapon, pylon, date, skip_types={WeaponType.LGB} - ) - if fallback is None: - del new_pylons[pylon_number] - else: - new_pylons[pylon_number] = fallback - self.pylons = new_pylons - - @classmethod - def convert_dcs_loadout_to_pylon_map( - cls, pylons: dict[int, dict[str, Any]] - ) -> dict[int, Weapon | None]: - return { - p["num"]: Weapon.with_clsid(p["CLSID"]) - for p in pylons.values() - # When unloading incompatible pylons (for example, some of the - # Mosquito's pylons cannot be loaded when other pylons are carrying - # rockets), DCS sometimes equips the empty string rather than - # unsetting the pylon. An unset pylon and the empty string appear to - # have identical behavior, and it's annoying to deal with weapons - # that pydcs doesn't know about, so just clear those pylons rather - # than explicitly handling "". - # https://github.com/dcs-liberation/dcs_liberation/issues/3171 - if p["CLSID"] != "" - } - - @classmethod - def iter_for(cls, flight: Flight) -> Iterator[Loadout]: - return cls.iter_for_aircraft(flight.unit_type) - - @classmethod - def iter_for_aircraft(cls, aircraft: AircraftType) -> Iterator[Loadout]: - # Dict of payload ID (numeric) to: - # - # { - # "name": The name the user set in the ME - # "pylons": List (as a dict) of dicts of: - # {"CLSID": class ID, "num": pylon number} - # "tasks": List (as a dict) of task IDs the payload is used by. - # } - payloads = aircraft.dcs_unit_type.load_payloads() - for payload in payloads.values(): - name = payload["name"] - try: - pylon_assignments = cls.convert_dcs_loadout_to_pylon_map( - payload["pylons"] - ) - except KeyError: - logging.exception( - "Ignoring %s loadout with invalid weapons: %s", - aircraft.variant_id, - name, - ) - continue - - yield Loadout( - name, - pylon_assignments, - date=None, - ) - - @classmethod - def default_loadout_names_for(cls, task: FlightType) -> Iterator[str]: - # This is a list of mappings from the FlightType of a Flight to the type of - # payload defined in the resources/payloads/UNIT_TYPE.lua file. A Flight has no - # concept of a PyDCS task, so COMMON_OVERRIDE cannot be used here. This is used - # in the payload editor, for setting the default loadout of an object. The left - # element is the FlightType name, and the right element is a tuple containing - # what is used in the lua file. Some aircraft differ from the standard loadout - # names, so those have been included here too. The priority goes from first to - # last - the first element in the tuple will be tried first, then the second, - # etc. - loadout_names = {t: [f"Liberation {t.value}"] for t in FlightType} - legacy_names = { - FlightType.TARCAP: ("CAP HEAVY", "CAP", "Liberation BARCAP"), - FlightType.BARCAP: ("CAP HEAVY", "CAP", "Liberation TARCAP"), - FlightType.CAS: ("CAS MAVERICK F", "CAS"), - FlightType.STRIKE: ("STRIKE",), - FlightType.ANTISHIP: ("ANTISHIP",), - FlightType.DEAD: ("DEAD",), - FlightType.SEAD: ("SEAD",), - FlightType.BAI: ("BAI",), - FlightType.OCA_RUNWAY: ("RUNWAY_ATTACK", "RUNWAY_STRIKE"), - FlightType.OCA_AIRCRAFT: ("OCA",), - } - for flight_type, names in legacy_names.items(): - loadout_names[flight_type].extend(names) - # A SEAD escort typically does not need a different loadout than a regular - # SEAD flight, so fall back to SEAD if needed. - loadout_names[FlightType.SEAD_ESCORT].extend(loadout_names[FlightType.SEAD]) - # Sweep and escort can fall back to TARCAP. - loadout_names[FlightType.ESCORT].extend(loadout_names[FlightType.TARCAP]) - loadout_names[FlightType.SWEEP].extend(loadout_names[FlightType.TARCAP]) - # Intercept can fall back to BARCAP. - loadout_names[FlightType.INTERCEPTION].extend(loadout_names[FlightType.BARCAP]) - # OCA/Aircraft falls back to BAI, which falls back to CAS. - loadout_names[FlightType.BAI].extend(loadout_names[FlightType.CAS]) - loadout_names[FlightType.OCA_AIRCRAFT].extend(loadout_names[FlightType.BAI]) - # DEAD also falls back to BAI. - loadout_names[FlightType.DEAD].extend(loadout_names[FlightType.BAI]) - # OCA/Runway falls back to Strike - loadout_names[FlightType.OCA_RUNWAY].extend(loadout_names[FlightType.STRIKE]) - yield from loadout_names[task] - - @classmethod - def default_for(cls, flight: Flight) -> Loadout: - return cls.default_for_task_and_aircraft( - flight.flight_type, flight.unit_type.dcs_unit_type - ) - - @classmethod - def default_for_task_and_aircraft( - cls, task: FlightType, dcs_unit_type: Type[FlyingType] - ) -> Loadout: - # Iterate through each possible payload type for a given aircraft. - # Some aircraft have custom loadouts that in aren't the standard set. - for name in cls.default_loadout_names_for(task): - # This operation is cached, but must be called before load_by_name will - # work. - dcs_unit_type.load_payloads() - payload = dcs_unit_type.loadout_by_name(name) - if payload is not None: - try: - # Pydcs returns the data in a different format for loadout_by_name() - # than it does for load_payloads(), for some reason. Convert this - # result to match the other so that we can reuse - # convert_dcs_loadout_to_pylon_map. - # - # loadout_by_name() returns a list of pairs, with the first item - # being the pylon index and the second being a dict with a single - # clsid key. - # - # Each element of load_payloads() pylons is a dict of dicts with - # both the CLSID key (yes, different case from the other API!) and a - # num key for the pylon index. The outer dict is a mapping for a lua - # table, so its keys are just indexes. - pylons = cls.convert_dcs_loadout_to_pylon_map( - { - i: {"num": n, "CLSID": p["clsid"]} - for i, (n, p) in enumerate(payload) - } - ) - except KeyError: - logging.exception( - "Ignoring %s loadout with invalid weapons: %s", - dcs_unit_type.id, - name, - ) - continue - return Loadout(name, pylons, date=None) - - # TODO: Try group.load_task_default_loadout(loadout_for_task) - return cls.empty_loadout() - - @classmethod - def empty_loadout(cls) -> Loadout: - return Loadout("Empty", {}, date=None) diff --git a/game/ato/package.py b/game/ato/package.py deleted file mode 100644 index a7a3469a9..000000000 --- a/game/ato/package.py +++ /dev/null @@ -1,231 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from datetime import datetime -from typing import Dict, Optional, TYPE_CHECKING - -from game.db import Database -from game.utils import Speed -from .closestairfields import ObjectiveDistanceCache -from .flight import Flight -from .flightplans.formation import FormationFlightPlan -from .flighttype import FlightType -from .packagewaypoints import PackageWaypoints -from .traveltime import TotEstimator - -if TYPE_CHECKING: - from game.theater import ControlPoint, MissionTarget - - -class Package: - """A mission package.""" - - def __init__( - self, target: MissionTarget, db: Database[Flight], auto_asap: bool = False - ) -> None: - self.target = target - self._db = db - - # True if the package ToT should be reset to ASAP whenever the player makes a - # change. This is really a UI property rather than a game property, but we want - # it to persist in the save. - self.auto_asap = auto_asap - self.flights: list[Flight] = [] - - # Desired TOT as an offset from mission start. Obviously datetime.min is bogus, - # but it's going to be replaced by whatever is scheduling the package very soon. - # TODO: Constructor should maybe take the current time and use that to preserve - # the old behavior? - self.time_over_target: datetime = datetime.min - self.waypoints: PackageWaypoints | None = None - - @property - def has_players(self) -> bool: - return any(flight.client_count for flight in self.flights) - - @property - def formation_speed(self) -> Optional[Speed]: - """The speed of the package when in formation. - - If none of the flights in the package will join a formation, this - returns None. This is not uncommon, since only strike-like (strike, - DEAD, anti-ship, BAI, etc.) flights and their escorts fly in formation. - Others (CAP and CAS, currently) will coordinate in target timing but - fly their own path to the target. - """ - speeds = [] - for flight in self.flights: - if isinstance(flight.flight_plan, FormationFlightPlan): - speeds.append(flight.flight_plan.best_flight_formation_speed) - if not speeds: - return None - return min(speeds) - - # TODO: Should depend on the type of escort. - # SEAD might be able to leave before CAP. - @property - def escort_start_time(self) -> datetime | None: - times = [] - for flight in self.flights: - waypoint = flight.flight_plan.request_escort_at() - if waypoint is None: - continue - tot = flight.flight_plan.tot_for_waypoint(waypoint) - if tot is None: - logging.error( - f"{flight} requested escort at {waypoint} but that " - "waypoint has no TOT. It may not be escorted." - ) - continue - times.append(tot) - if times: - return min(times) - return None - - @property - def escort_end_time(self) -> datetime | None: - times = [] - for flight in self.flights: - waypoint = flight.flight_plan.dismiss_escort_at() - if waypoint is None: - continue - tot = flight.flight_plan.tot_for_waypoint(waypoint) - if tot is None: - tot = flight.flight_plan.depart_time_for_waypoint(waypoint) - if tot is None: - logging.error( - f"{flight} dismissed escort at {waypoint} but that " - "waypoint has no TOT or departure time. It may not be " - "escorted." - ) - continue - times.append(tot) - if times: - return max(times) - return None - - @property - def mission_departure_time(self) -> datetime | None: - times = [] - for flight in self.flights: - times.append(flight.flight_plan.mission_departure_time) - if times: - return max(times) - return None - - def set_tot_asap(self, now: datetime) -> None: - self.time_over_target = TotEstimator(self).earliest_tot(now) - - def clamp_tot_for_current_time(self, now: datetime) -> None: - if not self.all_flights_waiting_for_start(): - return - - if not self.flights: - return - - earliest_startup_time = min(f.flight_plan.startup_time() for f in self.flights) - if earliest_startup_time < now: - self.time_over_target += now - earliest_startup_time - - def add_flight(self, flight: Flight) -> None: - """Adds a flight to the package.""" - self.flights.append(flight) - self._db.add(flight.id, flight) - - def remove_flight(self, flight: Flight) -> None: - """Removes a flight from the package.""" - self.flights.remove(flight) - self._db.remove(flight.id) - flight.return_pilots_and_aircraft() - if flight.cargo is not None: - flight.cargo.transport = None - if not self.flights: - self.waypoints = None - - @property - def primary_task(self) -> Optional[FlightType]: - if not self.flights: - return None - - flight_counts: Dict[FlightType, int] = defaultdict(lambda: 0) - for flight in self.flights: - flight_counts[flight.flight_type] += 1 - - # The package will contain a mix of mission types, but in general we can - # determine the goal of the mission because some mission types are more - # likely to be the main task than others. For example, a package with - # only CAP flights is a CAP package, a flight with CAP and strike is a - # strike package, a flight with CAP and DEAD is a DEAD package, and a - # flight with strike and SEAD is an OCA/Strike package. This list defines the - # priority order for package task names. The package's primary task will be the - # first task in this list that matches a flight in the package. - tasks_by_priority = [ - FlightType.CAS, - FlightType.STRIKE, - FlightType.ANTISHIP, - FlightType.OCA_AIRCRAFT, - FlightType.OCA_RUNWAY, - FlightType.BAI, - FlightType.DEAD, - FlightType.TRANSPORT, - FlightType.AIR_ASSAULT, - FlightType.SEAD, - FlightType.TARCAP, - FlightType.BARCAP, - FlightType.AEWC, - FlightType.FERRY, - FlightType.REFUELING, - FlightType.SWEEP, - FlightType.SEAD_ESCORT, - FlightType.ESCORT, - ] - for task in tasks_by_priority: - if flight_counts[task]: - return task - - # If we get here, our task_priorities list above is incomplete. Log the - # issue and return the type of *any* flight in the package. - some_mission = next(iter(self.flights)).flight_type - logging.warning(f"Unhandled mission type: {some_mission}") - return some_mission - - @property - def package_description(self) -> str: - """Generates a package description based on flight composition.""" - task = self.primary_task - if task is None: - return "No mission" - oca_strike_types = {FlightType.OCA_AIRCRAFT, FlightType.OCA_RUNWAY} - if task in oca_strike_types: - return "OCA Strike" - return str(task) - - def departure_closest_to_target(self) -> ControlPoint: - # We'll always have a package, but if this is being planned via the UI - # it could be the first flight in the package. - if not self.flights: - raise RuntimeError( - "Cannot determine source airfield for package with no flights" - ) - - # The package airfield is either the flight's airfield (when there is no - # package) or the closest airfield to the objective that is the - # departure airfield for some flight in the package. - cache = ObjectiveDistanceCache.get_closest_airfields(self.target) - for airfield in cache.operational_airfields: - for flight in self.flights: - if flight.departure == airfield: - return airfield - raise RuntimeError("Could not find any airfield assigned to this package") - - def all_flights_waiting_for_start(self) -> bool: - """Returns True if all flights in the package are waiting for start.""" - for flight in self.flights: - if not flight.state.is_waiting_for_start: - return False - return True - - def has_flight_with_task(self, task: FlightType) -> bool: - """Returns True if any flight in the package has the given task.""" - return task in (f.flight_type for f in self.flights) diff --git a/game/ato/packagewaypoints.py b/game/ato/packagewaypoints.py deleted file mode 100644 index c04505762..000000000 --- a/game/ato/packagewaypoints.py +++ /dev/null @@ -1,72 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from dcs import Point - -from game.ato.flightplans.waypointbuilder import WaypointBuilder -from game.flightplan import JoinZoneGeometry -from game.flightplan.ipsolver import IpSolver -from game.flightplan.refuelzonegeometry import RefuelZoneGeometry -from game.persistence.paths import waypoint_debug_directory -from game.utils import dcs_to_shapely_point - -if TYPE_CHECKING: - from game.ato import Package - from game.coalition import Coalition - - -@dataclass(frozen=True) -class PackageWaypoints: - join: Point - ingress: Point - split: Point - refuel: Point - - @staticmethod - def create( - package: Package, coalition: Coalition, dump_debug_info: bool - ) -> PackageWaypoints: - origin = package.departure_closest_to_target() - - # Start by picking the best IP for the attack. - ip_solver = IpSolver( - dcs_to_shapely_point(origin.position), - dcs_to_shapely_point(package.target.position), - coalition.doctrine, - coalition.opponent.threat_zone.all, - ) - ip_solver.set_debug_properties( - waypoint_debug_directory() / "IP", coalition.game.theater.terrain - ) - ingress_point_shapely = ip_solver.solve() - if dump_debug_info: - ip_solver.dump_debug_info() - - ingress_point = origin.position.new_in_same_map( - ingress_point_shapely.x, ingress_point_shapely.y - ) - - join_point = JoinZoneGeometry( - package.target.position, - origin.position, - ingress_point, - coalition, - ).find_best_join_point() - - refuel_point = RefuelZoneGeometry( - origin.position, - join_point, - coalition, - ).find_best_refuel_point() - - # And the split point based on the best route from the IP. Since that's no - # different than the best route *to* the IP, this is the same as the join point. - # TODO: Estimate attack completion point based on the IP and split from there? - return PackageWaypoints( - WaypointBuilder.perturb(join_point), - ingress_point, - WaypointBuilder.perturb(join_point), - refuel_point, - ) diff --git a/game/ato/starttype.py b/game/ato/starttype.py deleted file mode 100644 index e42e64029..000000000 --- a/game/ato/starttype.py +++ /dev/null @@ -1,15 +0,0 @@ -from enum import Enum, unique - - -@unique -class StartType(Enum): - """The start type for a Flight. - - This is distinct from dcs.mission.StartType because we need a fourth state: - IN_FLIGHT. - """ - - COLD = "Cold" - WARM = "Warm" - RUNWAY = "Runway" - IN_FLIGHT = "In Flight" diff --git a/game/ato/traveltime.py b/game/ato/traveltime.py deleted file mode 100644 index a56943ca2..000000000 --- a/game/ato/traveltime.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from typing import TYPE_CHECKING - -from game.utils import Distance, SPEED_OF_SOUND_AT_SEA_LEVEL, Speed, mach - -if TYPE_CHECKING: - from .flight import Flight - from .package import Package - - -class GroundSpeed: - @classmethod - def for_flight(cls, flight: Flight, altitude: Distance) -> Speed: - # TODO: Expose both a cruise speed and target speed. - # The cruise speed can be used for ascent, hold, join, and RTB to save - # on fuel, but mission speed will be fast enough to keep the flight - # safer. - - if flight.squadron.aircraft.cruise_speed is not None: - return mach(flight.squadron.aircraft.cruise_speed.mach(), altitude) - - # DCS's max speed is in kph at 0 MSL. - max_speed = flight.unit_type.max_speed - if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL: - # Aircraft is supersonic. Limit to mach 0.85 to conserve fuel and - # account for heavily loaded jets. - return mach(0.85, altitude) - - # For subsonic aircraft, assume the aircraft can reasonably perform at - # 80% of its maximum, and that it can maintain the same mach at altitude - # as it can at sea level. This probably isn't great assumption, but - # might. be sufficient given the wiggle room. We can come up with - # another heuristic if needed. - cruise_mach = max_speed.mach() * 0.85 - return mach(cruise_mach, altitude) - - -# TODO: Most if not all of this should move into FlightPlan. -class TotEstimator: - def __init__(self, package: Package) -> None: - self.package = package - - def earliest_tot(self, now: datetime) -> datetime: - if not self.package.flights: - return now - - return max(self.earliest_tot_for_flight(f, now) for f in self.package.flights) - - @staticmethod - def earliest_tot_for_flight(flight: Flight, now: datetime) -> datetime: - """Estimate the earliest time the flight can reach the target position. - - The interpretation of the TOT depends on the flight plan type. See the various - FlightPlan implementations for details. - - Args: - flight: The flight to get the earliest TOT for. - now: The current mission time. - - Returns: - The earliest possible TOT for the given flight. - """ - return now + flight.flight_plan.minimum_duration_from_start_to_tot() diff --git a/game/callsigns.py b/game/callsigns.py deleted file mode 100644 index a722606fc..000000000 --- a/game/callsigns.py +++ /dev/null @@ -1,35 +0,0 @@ -"""Support for working with DCS group callsigns.""" -import logging -import re -from typing import Any - -from dcs.unitgroup import FlyingGroup -from dcs.flyingunit import FlyingUnit - - -def callsign_for_support_unit(group: FlyingGroup[Any]) -> str: - # Either something like Overlord11 for Western AWACS, or else just a number. - # Convert to either "Overlord" or "Flight 123". - lead = group.units[0] - raw_callsign = lead.callsign_as_str() - try: - return f"Flight {int(raw_callsign)}" - except ValueError: - return raw_callsign.rstrip("1234567890") - - -def create_group_callsign_from_unit(lead: FlyingUnit) -> str: - raw_callsign = lead.callsign_as_str() - if not lead.callsign_is_western: - # Callsigns for non-Western countries are just a number per flight, - # similar to tail numbers. - return f"Flight {raw_callsign}" - - # Callsign from pydcs is in the format ``, - # where unit ID is guaranteed to be a single digit but the group ID may - # be more. - match = re.search(r"^(\D+)(\d+)(\d)$", raw_callsign) - if match is None: - logging.error(f"Could not parse unit callsign: {raw_callsign}") - return f"Flight {raw_callsign}" - return f"{match.group(1)} {match.group(2)}" diff --git a/game/campaignloader/__init__.py b/game/campaignloader/__init__.py deleted file mode 100644 index 937a39b23..000000000 --- a/game/campaignloader/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .campaign import Campaign -from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig diff --git a/game/campaignloader/campaign.py b/game/campaignloader/campaign.py deleted file mode 100644 index bbb91bf52..000000000 --- a/game/campaignloader/campaign.py +++ /dev/null @@ -1,204 +0,0 @@ -from __future__ import annotations - -import datetime -import logging -from collections.abc import Iterator -from dataclasses import dataclass -from pathlib import Path -from typing import Any, Dict, TYPE_CHECKING, Tuple - -import yaml -from packaging.version import Version - -from game import persistence -from game.profiling import logged_duration -from game.theater import ConflictTheater -from game.theater.iadsnetwork.iadsnetwork import IadsNetwork -from game.theater.theaterloader import TheaterLoader -from game.version import CAMPAIGN_FORMAT_VERSION -from .campaignairwingconfig import CampaignAirWingConfig -from .controlpointconfig import ControlPointConfig -from .factionrecommendation import FactionRecommendation -from .mizcampaignloader import MizCampaignLoader - -if TYPE_CHECKING: - from game.factions.factions import Factions - -PERF_FRIENDLY = 0 -PERF_MEDIUM = 1 -PERF_HARD = 2 -PERF_NASA = 3 -DEFAULT_BUDGET = 2000 - - -@dataclass(frozen=True) -class Campaign: - name: str - menu_thumbnail_dcs_relative_path: Path - authors: str - description: str - - #: The revision of the campaign format the campaign was built for. We do not attempt - #: to migrate old campaigns, but this is used to show a warning in the UI when - #: selecting a campaign that is not up to date. - version: Tuple[int, int] - - recommended_player_faction: FactionRecommendation - recommended_enemy_faction: FactionRecommendation - recommended_start_date: datetime.date | None - recommended_start_time: datetime.time | None - - recommended_player_money: int - recommended_enemy_money: int - recommended_player_income_multiplier: float - recommended_enemy_income_multiplier: float - - performance: int - data: Dict[str, Any] - path: Path - advanced_iads: bool - - @classmethod - def from_file(cls, path: Path) -> Campaign: - with path.open(encoding="utf-8") as campaign_file: - data = yaml.safe_load(campaign_file) - - version_field = data.get("version", "0") - try: - version = Version(version_field) - except TypeError: - logging.warning( - f"Non-string campaign version in {path}. Parse may be incorrect." - ) - version = Version(str(version_field)) - - start_date_raw = data.get("recommended_start_date") - # YAML automatically parses dates. - start_date: datetime.date | None - start_time: datetime.time | None = None - if isinstance(start_date_raw, datetime.datetime): - start_date = start_date_raw.date() - start_time = start_date_raw.time() - elif isinstance(start_date_raw, datetime.date): - start_date = start_date_raw - start_time = None - elif start_date_raw is None: - start_date = None - else: - raise RuntimeError( - f"Invalid value for recommended_start_date in {path}: {start_date_raw}" - ) - - return cls( - data["name"], - TheaterLoader(data["theater"].lower()).menu_thumbnail_dcs_relative_path, - data.get("authors", "???"), - data.get("description", ""), - (version.major, version.minor), - FactionRecommendation.from_field( - data.get("recommended_player_faction"), player=True - ), - FactionRecommendation.from_field( - data.get("recommended_enemy_faction"), player=False - ), - start_date, - start_time, - data.get("recommended_player_money", DEFAULT_BUDGET), - data.get("recommended_enemy_money", DEFAULT_BUDGET), - data.get("recommended_player_income_multiplier", 1.0), - data.get("recommended_enemy_income_multiplier", 1.0), - data.get("performance", 0), - data, - path, - data.get("advanced_iads", False), - ) - - def load_theater(self, advanced_iads: bool) -> ConflictTheater: - t = TheaterLoader(self.data["theater"].lower()).load() - - try: - miz = self.data["miz"] - except KeyError as ex: - raise RuntimeError( - "Old format (non-miz) campaigns are no longer supported." - ) from ex - - with logged_duration("Importing miz data"): - MizCampaignLoader( - self.path.parent / miz, - t, - dict( - ControlPointConfig.iter_from_data( - self.data.get("control_points", {}) - ) - ), - ).populate_theater() - - # TODO: Move into MizCampaignLoader so this doesn't have unknown initialization - # in ConflictTheater. - # Load IADS Config from campaign yaml - iads_data = self.data.get("iads_config", []) - t.iads_network = IadsNetwork(advanced_iads, iads_data) - return t - - def load_air_wing_config(self, theater: ConflictTheater) -> CampaignAirWingConfig: - try: - squadron_data = self.data["squadrons"] - except KeyError: - logging.warning(f"Campaign {self.name} does not define any squadrons") - return CampaignAirWingConfig({}) - return CampaignAirWingConfig.from_campaign_data(squadron_data, theater) - - @property - def is_out_of_date(self) -> bool: - """Returns True if this campaign is not up to date with the latest format. - - This is more permissive than is_from_future, which is sensitive to minor version - bumps (the old game definitely doesn't support the minor features added in the - new version, and the campaign may require them. However, the minor version only - indicates *optional* new features, so we do not need to mark out of date - campaigns as incompatible if they are within the same major version. - """ - return self.version[0] < CAMPAIGN_FORMAT_VERSION[0] - - @property - def is_from_future(self) -> bool: - """Returns True if this campaign is newer than the supported format.""" - return self.version > CAMPAIGN_FORMAT_VERSION - - @property - def is_compatible(self) -> bool: - """Returns True is this campaign was built for this version of the game.""" - if self.version == (0, 0): - return False - if self.is_out_of_date: - return False - if self.is_from_future: - return False - return True - - def register_campaign_specific_factions(self, factions: Factions) -> None: - self.recommended_player_faction.register_campaign_specific_faction(factions) - self.recommended_enemy_faction.register_campaign_specific_faction(factions) - - @staticmethod - def iter_campaigns_in_dir(path: Path) -> Iterator[Path]: - yield from path.glob("*.yaml") - yield from path.glob("*.json") - - @classmethod - def iter_campaign_defs(cls) -> Iterator[Path]: - yield from cls.iter_campaigns_in_dir( - Path(persistence.base_path()) / "Liberation/Campaigns" - ) - yield from cls.iter_campaigns_in_dir(Path("resources/campaigns")) - - @classmethod - def load_each(cls) -> Iterator[Campaign]: - for path in cls.iter_campaign_defs(): - try: - logging.debug(f"Loading campaign from {path}...") - campaign = Campaign.from_file(path) - yield campaign - except RuntimeError: - logging.exception(f"Unable to load campaign from {path}") diff --git a/game/campaignloader/campaignairwingconfig.py b/game/campaignloader/campaignairwingconfig.py deleted file mode 100644 index 6146624e7..000000000 --- a/game/campaignloader/campaignairwingconfig.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from collections import defaultdict -from dataclasses import dataclass -from typing import Any, Optional, TYPE_CHECKING, Union - -from game.ato.flighttype import FlightType -from game.theater.controlpoint import ControlPoint - -if TYPE_CHECKING: - from game.theater import ConflictTheater - - -DEFAULT_SQUADRON_SIZE = 12 - - -@dataclass(frozen=True) -class SquadronConfig: - primary: FlightType - secondary: list[FlightType] - aircraft: list[str] - max_size: int - - name: Optional[str] - nickname: Optional[str] - female_pilot_percentage: Optional[int] - - @property - def auto_assignable(self) -> set[FlightType]: - return set(self.secondary) | {self.primary} - - @classmethod - def from_data(cls, data: dict[str, Any]) -> SquadronConfig: - secondary_raw = data.get("secondary") - if secondary_raw is None: - secondary = [] - elif isinstance(secondary_raw, str): - secondary = cls.expand_secondary_alias(secondary_raw) - else: - secondary = [FlightType(s) for s in secondary_raw] - - return SquadronConfig( - FlightType(data["primary"]), - secondary, - data.get("aircraft", []), - data.get("size", DEFAULT_SQUADRON_SIZE), - data.get("name", None), - data.get("nickname", None), - data.get("female_pilot_percentage", None), - ) - - @staticmethod - def expand_secondary_alias(alias: str) -> list[FlightType]: - if alias == "any": - return list(FlightType) - elif alias == "air-to-air": - return [t for t in FlightType if t.is_air_to_air] - elif alias == "air-to-ground": - return [t for t in FlightType if t.is_air_to_ground] - raise KeyError(f"Unknown secondary mission type: {alias}") - - -@dataclass(frozen=True) -class CampaignAirWingConfig: - by_location: dict[ControlPoint, list[SquadronConfig]] - - @classmethod - def from_campaign_data( - cls, data: dict[Union[str, int], Any], theater: ConflictTheater - ) -> CampaignAirWingConfig: - by_location: dict[ControlPoint, list[SquadronConfig]] = defaultdict(list) - for base_id, squadron_configs in data.items(): - if isinstance(base_id, int): - base = theater.find_control_point_by_airport_id(base_id) - else: - base = theater.control_point_named(base_id) - - for squadron_data in squadron_configs: - by_location[base].append(SquadronConfig.from_data(squadron_data)) - - return CampaignAirWingConfig(by_location) diff --git a/game/campaignloader/controlpointbuilder.py b/game/campaignloader/controlpointbuilder.py deleted file mode 100644 index 982f6b7b2..000000000 --- a/game/campaignloader/controlpointbuilder.py +++ /dev/null @@ -1,90 +0,0 @@ -from dcs import Point -from dcs.terrain import Airport - -from game.campaignloader.controlpointconfig import ControlPointConfig -from game.theater import ( - Airfield, - Carrier, - ConflictTheater, - ControlPoint, - Fob, - Lha, - OffMapSpawn, -) - - -class ControlPointBuilder: - def __init__( - self, theater: ConflictTheater, configs: dict[str | int, ControlPointConfig] - ) -> None: - self.theater = theater - self.config = configs - - def create_airfield(self, airport: Airport) -> Airfield: - cp = Airfield(airport, self.theater, starts_blue=airport.is_blue()) - - # Use the unlimited aircraft option to determine if an airfield should - # be owned by the player when the campaign is "inverted". - cp.captured_invert = airport.unlimited_aircrafts - - self._apply_config(airport.id, cp) - return cp - - def create_fob( - self, - name: str, - position: Point, - theater: ConflictTheater, - starts_blue: bool, - captured_invert: bool, - ) -> Fob: - cp = Fob(name, position, theater, starts_blue) - cp.captured_invert = captured_invert - self._apply_config(name, cp) - return cp - - def create_carrier( - self, - name: str, - position: Point, - theater: ConflictTheater, - starts_blue: bool, - captured_invert: bool, - ) -> Carrier: - cp = Carrier(name, position, theater, starts_blue) - cp.captured_invert = captured_invert - self._apply_config(name, cp) - return cp - - def create_lha( - self, - name: str, - position: Point, - theater: ConflictTheater, - starts_blue: bool, - captured_invert: bool, - ) -> Lha: - cp = Lha(name, position, theater, starts_blue) - cp.captured_invert = captured_invert - self._apply_config(name, cp) - return cp - - def create_off_map( - self, - name: str, - position: Point, - theater: ConflictTheater, - starts_blue: bool, - captured_invert: bool, - ) -> OffMapSpawn: - cp = OffMapSpawn(name, position, theater, starts_blue) - cp.captured_invert = captured_invert - self._apply_config(name, cp) - return cp - - def _apply_config(self, cp_id: str | int, control_point: ControlPoint) -> None: - config = self.config.get(cp_id) - if config is None: - return - - control_point.ferry_only = config.ferry_only diff --git a/game/campaignloader/controlpointconfig.py b/game/campaignloader/controlpointconfig.py deleted file mode 100644 index 468673b95..000000000 --- a/game/campaignloader/controlpointconfig.py +++ /dev/null @@ -1,21 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass -from typing import Any - - -@dataclass(frozen=True) -class ControlPointConfig: - ferry_only: bool - - @staticmethod - def from_data(data: dict[str, Any]) -> ControlPointConfig: - return ControlPointConfig(ferry_only=data.get("ferry_only", False)) - - @staticmethod - def iter_from_data( - data: dict[str | int, Any] - ) -> Iterator[tuple[str | int, ControlPointConfig]]: - for name_or_id, cp_data in data.items(): - yield name_or_id, ControlPointConfig.from_data(cp_data) diff --git a/game/campaignloader/defaultsquadronassigner.py b/game/campaignloader/defaultsquadronassigner.py deleted file mode 100644 index 00e0cd730..000000000 --- a/game/campaignloader/defaultsquadronassigner.py +++ /dev/null @@ -1,174 +0,0 @@ -from __future__ import annotations - -import logging -from typing import Optional, TYPE_CHECKING - -from game.squadrons import Squadron -from game.squadrons.squadrondef import SquadronDef -from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig -from ..ato.flighttype import FlightType -from ..dcs.aircrafttype import AircraftType -from ..theater import ControlPoint - -if TYPE_CHECKING: - from game import Game - from game.coalition import Coalition - - -class DefaultSquadronAssigner: - def __init__( - self, config: CampaignAirWingConfig, game: Game, coalition: Coalition - ) -> None: - self.config = config - self.game = game - self.coalition = coalition - self.air_wing = coalition.air_wing - - def assign(self) -> None: - for control_point in self.game.theater.control_points_for( - self.coalition.player - ): - for squadron_config in self.config.by_location[control_point]: - squadron_def = self.override_squadron_defaults( - self.find_squadron_for(squadron_config, control_point), - squadron_config, - ) - - if squadron_def is None: - logging.info( - f"{self.coalition.faction.name} has no aircraft compatible " - f"with {squadron_config.primary} at {control_point}" - ) - continue - - squadron = Squadron.create_from( - squadron_def, - squadron_config.primary, - squadron_config.max_size, - control_point, - self.coalition, - self.game, - ) - squadron.set_auto_assignable_mission_types( - squadron_config.auto_assignable - ) - self.air_wing.add_squadron(squadron) - - def find_squadron_for( - self, config: SquadronConfig, control_point: ControlPoint - ) -> Optional[SquadronDef]: - for preferred_aircraft in config.aircraft: - squadron_def = self.find_preferred_squadron( - preferred_aircraft, config.primary, control_point - ) - if squadron_def is not None: - return squadron_def - - # If we didn't find any of the preferred types (if the list contains only - # squadrons or aircraft unavailable to the coalition) we should use any squadron - # compatible with the primary task. - squadron_def = self.find_squadron_for_task(config.primary, control_point) - if squadron_def is not None: - return squadron_def - - # If we can't find any pre-made squadron matching the requirement, we should - # create one. - return self.air_wing.squadron_def_generator.generate_for_task( - config.primary, control_point - ) - - def find_preferred_squadron( - self, preferred_aircraft: str, task: FlightType, control_point: ControlPoint - ) -> Optional[SquadronDef]: - # Attempt to find a squadron with the name in the request. - squadron_def = self.find_squadron_by_name( - preferred_aircraft, task, control_point - ) - if squadron_def is not None: - return squadron_def - - # If the name didn't match a squadron available to this coalition, try to find - # an aircraft with the matching name that meets the requirements. - try: - aircraft = AircraftType.named(preferred_aircraft) - except KeyError: - logging.warning( - "%s is neither a compatible squadron or a known aircraft type, " - "ignoring", - preferred_aircraft, - ) - return None - - if aircraft not in self.coalition.faction.aircrafts: - return None - - squadron_def = self.find_squadron_for_airframe(aircraft, task, control_point) - if squadron_def is not None: - return squadron_def - - # No premade squadron available for this aircraft that meets the requirements, - # so generate one if possible. - return self.air_wing.squadron_def_generator.generate_for_aircraft(aircraft) - - @staticmethod - def squadron_compatible_with( - squadron: SquadronDef, - task: FlightType, - control_point: ControlPoint, - ignore_base_preference: bool = False, - ) -> bool: - if ignore_base_preference: - return control_point.can_operate(squadron.aircraft) - return squadron.operates_from(control_point) and squadron.capable_of(task) - - def find_squadron_for_airframe( - self, aircraft: AircraftType, task: FlightType, control_point: ControlPoint - ) -> Optional[SquadronDef]: - for squadron in self.air_wing.squadron_defs[aircraft]: - if not squadron.claimed and self.squadron_compatible_with( - squadron, task, control_point - ): - return squadron - return None - - def find_squadron_by_name( - self, name: str, task: FlightType, control_point: ControlPoint - ) -> Optional[SquadronDef]: - for squadrons in self.air_wing.squadron_defs.values(): - for squadron in squadrons: - if ( - not squadron.claimed - and squadron.name == name - and self.squadron_compatible_with( - squadron, task, control_point, ignore_base_preference=True - ) - ): - return squadron - return None - - def find_squadron_for_task( - self, task: FlightType, control_point: ControlPoint - ) -> Optional[SquadronDef]: - for squadrons in self.air_wing.squadron_defs.values(): - for squadron in squadrons: - if not squadron.claimed and self.squadron_compatible_with( - squadron, task, control_point - ): - return squadron - return None - - @staticmethod - def override_squadron_defaults( - squadron_def: Optional[SquadronDef], config: SquadronConfig - ) -> Optional[SquadronDef]: - if squadron_def is None: - return None - - if config.name is not None: - squadron_def.name = config.name - if config.nickname is not None: - squadron_def.nickname = config.nickname - if config.female_pilot_percentage is not None: - squadron_def.female_pilot_percentage = config.female_pilot_percentage - - return squadron_def diff --git a/game/campaignloader/factionrecommendation.py b/game/campaignloader/factionrecommendation.py deleted file mode 100644 index b9b2d8413..000000000 --- a/game/campaignloader/factionrecommendation.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Any, TYPE_CHECKING - -from game.factions import Faction - -if TYPE_CHECKING: - from game.factions.factions import Factions - - -class FactionRecommendation(ABC): - def __init__(self, name: str) -> None: - self.name = name - - @abstractmethod - def register_campaign_specific_faction(self, factions: Factions) -> None: - ... - - @abstractmethod - def get_faction(self, factions: Factions) -> Faction: - ... - - @staticmethod - def from_field( - data: str | dict[str, Any] | None, player: bool - ) -> FactionRecommendation: - if data is None: - name = "USA 2005" if player else "Russia 1990" - return BuiltinFactionRecommendation(name) - if isinstance(data, str): - return BuiltinFactionRecommendation(data) - return CampaignDefinedFactionRecommendation(Faction.from_dict(data)) - - -class BuiltinFactionRecommendation(FactionRecommendation): - def register_campaign_specific_faction(self, factions: Factions) -> None: - pass - - def get_faction(self, factions: Factions) -> Faction: - return factions.get_by_name(self.name) - - -class CampaignDefinedFactionRecommendation(FactionRecommendation): - def __init__(self, faction: Faction) -> None: - super().__init__(faction.name) - self.faction = faction - - def register_campaign_specific_faction(self, factions: Factions) -> None: - factions.add_campaign_defined(self.faction) - - def get_faction(self, factions: Factions) -> Faction: - return self.faction diff --git a/game/campaignloader/mizcampaignloader.py b/game/campaignloader/mizcampaignloader.py deleted file mode 100644 index 87cc42c26..000000000 --- a/game/campaignloader/mizcampaignloader.py +++ /dev/null @@ -1,459 +0,0 @@ -from __future__ import annotations - -import itertools -from functools import cached_property -from pathlib import Path -from typing import Iterator, List, TYPE_CHECKING -from uuid import UUID - -from dcs import Mission -from dcs.countries import CombinedJointTaskForcesBlue, CombinedJointTaskForcesRed -from dcs.country import Country -from dcs.planes import F_15C -from dcs.ships import HandyWind, LHA_Tarawa, Stennis, USS_Arleigh_Burke_IIa -from dcs.statics import Fortification, Warehouse -from dcs.unitgroup import PlaneGroup, ShipGroup, StaticGroup, VehicleGroup -from dcs.vehicles import AirDefence, Armor, MissilesSS, Unarmed - -from game.campaignloader.controlpointbuilder import ControlPointBuilder -from game.campaignloader.controlpointconfig import ControlPointConfig -from game.profiling import logged_duration -from game.scenery_group import SceneryGroup -from game.theater.controlpoint import ControlPoint -from game.theater.presetlocation import PresetLocation - -if TYPE_CHECKING: - from game.theater.conflicttheater import ConflictTheater - - -class MizCampaignLoader: - BLUE_COUNTRY = CombinedJointTaskForcesBlue() - RED_COUNTRY = CombinedJointTaskForcesRed() - - OFF_MAP_UNIT_TYPE = F_15C.id - - CV_UNIT_TYPE = Stennis.id - LHA_UNIT_TYPE = LHA_Tarawa.id - FRONT_LINE_UNIT_TYPE = Armor.M_113.id - SHIPPING_LANE_UNIT_TYPE = HandyWind.id - - FOB_UNIT_TYPE = Unarmed.SKP_11.id - FARP_HELIPADS_TYPE = ["Invisible FARP", "SINGLE_HELIPAD"] - - OFFSHORE_STRIKE_TARGET_UNIT_TYPE = Fortification.Oil_platform.id - SHIP_UNIT_TYPE = USS_Arleigh_Burke_IIa.id - MISSILE_SITE_UNIT_TYPE = MissilesSS.Scud_B.id - COASTAL_DEFENSE_UNIT_TYPE = MissilesSS.Hy_launcher.id - - COMMAND_CENTER_UNIT_TYPE = Fortification._Command_Center.id - CONNECTION_NODE_UNIT_TYPE = Fortification.Comms_tower_M.id - POWER_SOURCE_UNIT_TYPE = Fortification.GeneratorF.id - - # Multiple options for air defenses so campaign designers can more accurately see - # the coverage of their IADS for the expected type. - LONG_RANGE_SAM_UNIT_TYPES = { - AirDefence.Patriot_ln.id, - AirDefence.S_300PS_5P85C_ln.id, - AirDefence.S_300PS_5P85D_ln.id, - } - - MEDIUM_RANGE_SAM_UNIT_TYPES = { - AirDefence.Hawk_ln.id, - AirDefence.S_75M_Volhov.id, - AirDefence.X_5p73_s_125_ln.id, - } - - SHORT_RANGE_SAM_UNIT_TYPES = { - AirDefence.M1097_Avenger.id, - AirDefence.Rapier_fsa_launcher.id, - AirDefence.X_2S6_Tunguska.id, - AirDefence.Strela_1_9P31.id, - } - - AAA_UNIT_TYPES = { - AirDefence.Flak18.id, - AirDefence.Vulcan.id, - AirDefence.ZSU_23_4_Shilka.id, - } - - EWR_UNIT_TYPE = AirDefence.X_1L13_EWR.id - - ARMOR_GROUP_UNIT_TYPE = Armor.M_1_Abrams.id - - FACTORY_UNIT_TYPE = Fortification.Workshop_A.id - - AMMUNITION_DEPOT_UNIT_TYPE = Warehouse._Ammunition_depot.id - - STRIKE_TARGET_UNIT_TYPE = Fortification.Tech_combine.id - - def __init__( - self, - miz: Path, - theater: ConflictTheater, - control_point_configs: dict[str | int, ControlPointConfig], - ) -> None: - self.theater = theater - self.control_point_builder = ControlPointBuilder(theater, control_point_configs) - self.mission = Mission() - with logged_duration("Loading miz"): - self.mission.load_file(str(miz)) - - # If there are no red carriers there usually aren't red units. Make sure - # both countries are initialized so we don't have to deal with None. - if self.mission.country(self.BLUE_COUNTRY.name) is None: - self.mission.coalition["blue"].add_country(self.BLUE_COUNTRY) - if self.mission.country(self.RED_COUNTRY.name) is None: - self.mission.coalition["red"].add_country(self.RED_COUNTRY) - - def country(self, blue: bool) -> Country: - country = self.mission.country( - self.BLUE_COUNTRY.name if blue else self.RED_COUNTRY.name - ) - # Should be guaranteed because we initialized them. - assert country - return country - - @property - def blue(self) -> Country: - return self.country(blue=True) - - @property - def red(self) -> Country: - return self.country(blue=False) - - def off_map_spawns(self, blue: bool) -> Iterator[PlaneGroup]: - for group in self.country(blue).plane_group: - if group.units[0].type == self.OFF_MAP_UNIT_TYPE: - yield group - - def carriers(self, blue: bool) -> Iterator[ShipGroup]: - for group in self.country(blue).ship_group: - if group.units[0].type == self.CV_UNIT_TYPE: - yield group - - def lhas(self, blue: bool) -> Iterator[ShipGroup]: - for group in self.country(blue).ship_group: - if group.units[0].type == self.LHA_UNIT_TYPE: - yield group - - def fobs(self, blue: bool) -> Iterator[VehicleGroup]: - for group in self.country(blue).vehicle_group: - if group.units[0].type == self.FOB_UNIT_TYPE: - yield group - - @property - def ships(self) -> Iterator[ShipGroup]: - for group in self.red.ship_group: - if group.units[0].type == self.SHIP_UNIT_TYPE: - yield group - - @property - def offshore_strike_targets(self) -> Iterator[StaticGroup]: - for group in self.red.static_group: - if group.units[0].type == self.OFFSHORE_STRIKE_TARGET_UNIT_TYPE: - yield group - - @property - def missile_sites(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type == self.MISSILE_SITE_UNIT_TYPE: - yield group - - @property - def coastal_defenses(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type == self.COASTAL_DEFENSE_UNIT_TYPE: - yield group - - @property - def long_range_sams(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type in self.LONG_RANGE_SAM_UNIT_TYPES: - yield group - - @property - def medium_range_sams(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type in self.MEDIUM_RANGE_SAM_UNIT_TYPES: - yield group - - @property - def short_range_sams(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type in self.SHORT_RANGE_SAM_UNIT_TYPES: - yield group - - @property - def aaa(self) -> Iterator[VehicleGroup]: - for group in itertools.chain(self.blue.vehicle_group, self.red.vehicle_group): - if group.units[0].type in self.AAA_UNIT_TYPES: - yield group - - @property - def ewrs(self) -> Iterator[VehicleGroup]: - for group in self.red.vehicle_group: - if group.units[0].type in self.EWR_UNIT_TYPE: - yield group - - @property - def armor_groups(self) -> Iterator[VehicleGroup]: - for group in itertools.chain(self.blue.vehicle_group, self.red.vehicle_group): - if group.units[0].type in self.ARMOR_GROUP_UNIT_TYPE: - yield group - - @property - def helipads(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.FARP_HELIPADS_TYPE: - yield group - - @property - def factories(self) -> Iterator[StaticGroup]: - for group in self.blue.static_group: - if group.units[0].type in self.FACTORY_UNIT_TYPE: - yield group - - @property - def ammunition_depots(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.AMMUNITION_DEPOT_UNIT_TYPE: - yield group - - @property - def strike_targets(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.STRIKE_TARGET_UNIT_TYPE: - yield group - - @property - def scenery(self) -> List[SceneryGroup]: - return SceneryGroup.from_trigger_zones(z for z in self.mission.triggers.zones()) - - @cached_property - def control_points(self) -> dict[UUID, ControlPoint]: - control_points: dict[UUID, ControlPoint] = {} - control_point: ControlPoint - for airport in self.mission.terrain.airport_list(): - if airport.is_blue() or airport.is_red(): - control_point = self.control_point_builder.create_airfield(airport) - control_points[control_point.id] = control_point - - for blue in (False, True): - for group in self.off_map_spawns(blue): - control_point = self.control_point_builder.create_off_map( - str(group.name), - group.position, - self.theater, - starts_blue=blue, - captured_invert=group.late_activation, - ) - control_points[control_point.id] = control_point - for ship in self.carriers(blue): - control_point = self.control_point_builder.create_carrier( - ship.name, - ship.position, - self.theater, - starts_blue=blue, - captured_invert=ship.late_activation, - ) - control_points[control_point.id] = control_point - for ship in self.lhas(blue): - control_point = self.control_point_builder.create_lha( - ship.name, - ship.position, - self.theater, - starts_blue=blue, - captured_invert=ship.late_activation, - ) - control_points[control_point.id] = control_point - for fob in self.fobs(blue): - control_point = self.control_point_builder.create_fob( - str(fob.name), - fob.position, - self.theater, - starts_blue=blue, - captured_invert=fob.late_activation, - ) - control_points[control_point.id] = control_point - - return control_points - - @property - def front_line_path_groups(self) -> Iterator[VehicleGroup]: - for group in self.country(blue=True).vehicle_group: - if group.units[0].type == self.FRONT_LINE_UNIT_TYPE: - yield group - - @property - def shipping_lane_groups(self) -> Iterator[ShipGroup]: - for group in self.country(blue=True).ship_group: - if group.units[0].type == self.SHIPPING_LANE_UNIT_TYPE: - yield group - - @property - def iads_command_centers(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.COMMAND_CENTER_UNIT_TYPE: - yield group - - @property - def iads_connection_nodes(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.CONNECTION_NODE_UNIT_TYPE: - yield group - - @property - def iads_power_sources(self) -> Iterator[StaticGroup]: - for group in itertools.chain(self.blue.static_group, self.red.static_group): - if group.units[0].type in self.POWER_SOURCE_UNIT_TYPE: - yield group - - def add_supply_routes(self) -> None: - for group in self.front_line_path_groups: - # The unit will have its first waypoint at the source CP and the final - # waypoint at the destination CP. Each waypoint defines the path of the - # cargo ship. - waypoints = [p.position for p in group.points] - origin = self.theater.closest_control_point(waypoints[0]) - if origin is None: - raise RuntimeError( - f"No control point near the first waypoint of {group.name}" - ) - destination = self.theater.closest_control_point(waypoints[-1]) - if destination is None: - raise RuntimeError( - f"No control point near the final waypoint of {group.name}" - ) - - self.control_points[origin.id].create_convoy_route(destination, waypoints) - self.control_points[destination.id].create_convoy_route( - origin, list(reversed(waypoints)) - ) - - def add_shipping_lanes(self) -> None: - for group in self.shipping_lane_groups: - # The unit will have its first waypoint at the source CP and the final - # waypoint at the destination CP. Each waypoint defines the path of the - # cargo ship. - waypoints = [p.position for p in group.points] - origin = self.theater.closest_control_point(waypoints[0]) - if origin is None: - raise RuntimeError( - f"No control point near the first waypoint of {group.name}" - ) - destination = self.theater.closest_control_point(waypoints[-1]) - if destination is None: - raise RuntimeError( - f"No control point near the final waypoint of {group.name}" - ) - - self.control_points[origin.id].create_shipping_lane(destination, waypoints) - self.control_points[destination.id].create_shipping_lane( - origin, list(reversed(waypoints)) - ) - - def add_preset_locations(self) -> None: - for static in self.offshore_strike_targets: - closest = self.theater.closest_control_point(static.position) - closest.preset_locations.offshore_strike_locations.append( - PresetLocation.from_group(static) - ) - - for ship in self.ships: - closest = self.theater.closest_control_point( - ship.position, allow_naval=True - ) - closest.preset_locations.ships.append(PresetLocation.from_group(ship)) - - for group in self.missile_sites: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.missile_sites.append( - PresetLocation.from_group(group) - ) - - for group in self.coastal_defenses: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.coastal_defenses.append( - PresetLocation.from_group(group) - ) - - for group in self.long_range_sams: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.long_range_sams.append( - PresetLocation.from_group(group) - ) - - for group in self.medium_range_sams: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.medium_range_sams.append( - PresetLocation.from_group(group) - ) - - for group in self.short_range_sams: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.short_range_sams.append( - PresetLocation.from_group(group) - ) - - for group in self.aaa: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.aaa.append(PresetLocation.from_group(group)) - - for group in self.ewrs: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.ewrs.append(PresetLocation.from_group(group)) - - for group in self.armor_groups: - closest = self.theater.closest_control_point(group.position) - closest.preset_locations.armor_groups.append( - PresetLocation.from_group(group) - ) - - for static in self.helipads: - closest = self.theater.closest_control_point(static.position) - closest.helipads.append(PresetLocation.from_group(static)) - - for static in self.factories: - closest = self.theater.closest_control_point(static.position) - closest.preset_locations.factories.append(PresetLocation.from_group(static)) - - for static in self.ammunition_depots: - closest = self.theater.closest_control_point(static.position) - closest.preset_locations.ammunition_depots.append( - PresetLocation.from_group(static) - ) - - for static in self.strike_targets: - closest = self.theater.closest_control_point(static.position) - closest.preset_locations.strike_locations.append( - PresetLocation.from_group(static) - ) - - for iads_command_center in self.iads_command_centers: - closest = self.theater.closest_control_point(iads_command_center.position) - closest.preset_locations.iads_command_center.append( - PresetLocation.from_group(iads_command_center) - ) - - for iads_connection_node in self.iads_connection_nodes: - closest = self.theater.closest_control_point(iads_connection_node.position) - closest.preset_locations.iads_connection_node.append( - PresetLocation.from_group(iads_connection_node) - ) - - for iads_power_source in self.iads_power_sources: - closest = self.theater.closest_control_point(iads_power_source.position) - closest.preset_locations.iads_power_source.append( - PresetLocation.from_group(iads_power_source) - ) - - for scenery_group in self.scenery: - closest = self.theater.closest_control_point(scenery_group.centroid) - closest.preset_locations.scenery.append(scenery_group) - - def populate_theater(self) -> None: - for control_point in self.control_points.values(): - self.theater.add_controlpoint(control_point) - self.add_preset_locations() - self.add_supply_routes() - self.add_shipping_lanes() diff --git a/game/campaignloader/squadrondefgenerator.py b/game/campaignloader/squadrondefgenerator.py deleted file mode 100644 index 52eb6726b..000000000 --- a/game/campaignloader/squadrondefgenerator.py +++ /dev/null @@ -1,325 +0,0 @@ -from __future__ import annotations - -import itertools -import random -from typing import Optional, TYPE_CHECKING - -from game.ato.flighttype import FlightType -from game.dcs.aircrafttype import AircraftType -from game.squadrons.operatingbases import OperatingBases -from game.squadrons.squadrondef import SquadronDef -from game.theater import ControlPoint - -if TYPE_CHECKING: - from game.factions.faction import Faction - - -class SquadronDefGenerator: - def __init__(self, faction: Faction) -> None: - self.faction = faction - self.count = itertools.count(1) - self.used_nicknames: set[str] = set() - - def generate_for_task( - self, task: FlightType, control_point: ControlPoint - ) -> Optional[SquadronDef]: - aircraft_choice: Optional[AircraftType] = None - for aircraft in AircraftType.priority_list_for_task(task): - if aircraft not in self.faction.aircrafts: - continue - if not control_point.can_operate(aircraft): - continue - aircraft_choice = aircraft - # 50/50 chance to keep looking for an aircraft that isn't as far up the - # priority list to maintain some unit variety. - if random.choice([True, False]): - break - - if aircraft_choice is None: - return None - return self.generate_for_aircraft(aircraft_choice) - - def generate_for_aircraft(self, aircraft: AircraftType) -> SquadronDef: - return SquadronDef( - name=f"Squadron {next(self.count):03}", - nickname=self.random_nickname(), - country=self.faction.country, - role="Flying Squadron", - aircraft=aircraft, - livery=None, - auto_assignable_mission_types=set(aircraft.iter_task_capabilities()), - operating_bases=OperatingBases.default_for_aircraft(aircraft), - female_pilot_percentage=6, - pilot_pool=[], - ) - - @staticmethod - def _make_random_nickname() -> str: - from game.naming import ANIMALS - - animal = random.choice(ANIMALS) - adjective = random.choice( - ( - None, - "Aggressive", - "Alpha", - "Ancient", - "Angelic", - "Angry", - "Apoplectic", - "Aquamarine", - "Astral", - "Avenging", - "Azure", - "Badass", - "Barbaric", - "Battle", - "Battling", - "Bellicose", - "Belligerent", - "Big", - "Bionic", - "Black", - "Bladed", - "Blazoned", - "Blood", - "Bloody", - "Blue", - "Bold", - "Boxing", - "Brash", - "Brass", - "Brave", - "Brazen", - "Bronze", - "Brown", - "Brutal", - "Burning", - "Buzzing", - "Celestial", - "Clever", - "Cloud", - "Cobalt", - "Copper", - "Coral", - "Crazy", - "Crimson", - "Crouching", - "Cursed", - "Cyan", - "Danger", - "Dangerous", - "Dapper", - "Daring", - "Dark", - "Dawn", - "Day", - "Deadly", - "Death", - "Defiant", - "Demon", - "Desert", - "Devil", - "Devil's", - "Diabolical", - "Diamond", - "Dire", - "Dirty", - "Doom", - "Doomed", - "Double", - "Drunken", - "Dusk", - "Dusty", - "Eager", - "Ebony", - "Electric", - "Emerald", - "Eternal", - "Evil", - "Faithful", - "Famous", - "Fanged", - "Fearless", - "Feisty", - "Ferocious", - "Fierce", - "Fiery", - "Fighting", - "Fire", - "First", - "Flame", - "Flaming", - "Flying", - "Forest", - "Frenzied", - "Frosty", - "Frozen", - "Furious", - "Gallant", - "Ghost", - "Giant", - "Gigantic", - "Glaring", - "Global", - "Gold", - "Golden", - "Green", - "Grey", - "Grim", - "Grizzly", - "Growling", - "Grumpy", - "Hammer", - "Hard", - "Hardy", - "Heavy", - "Hell", - "Hell's", - "Hidden", - "Homicidal", - "Hostile", - "Howling", - "Hyper", - "Ice", - "Icy", - "Immortal", - "Indignant", - "Infamous", - "Invincible", - "Iron", - "Jolly", - "Laser", - "Lava", - "Lavender", - "Lethal", - "Light", - "Lightning", - "Livid", - "Lucky", - "Mad", - "Magenta", - "Magma", - "Maroon", - "Menacing", - "Merciless", - "Metal", - "Midnight", - "Mighty", - "Mithril", - "Mocking", - "Moon", - "Mountain", - "Muddy", - "Nasty", - "Naughty", - "Night", - "Nova", - "Nutty", - "Obsidian", - "Ocean", - "Oddball", - "Old", - "Omega", - "Onyx", - "Orange", - "Perky", - "Pink", - "Power", - "Prickly", - "Proud", - "Puckered", - "Pugnacious", - "Puking", - "Purple", - "Ragged", - "Raging", - "Rainbow", - "Rampant", - "Razor", - "Ready", - "Reaper", - "Reckless", - "Red", - "Roaring", - "Rocky", - "Rolling", - "Royal", - "Rusty", - "Sable", - "Salty", - "Sand", - "Sarcastic", - "Saucy", - "Scarlet", - "Scarred", - "Scary", - "Screaming", - "Scythed", - "Shadow", - "Shiny", - "Shocking", - "Silver", - "Sky", - "Smoke", - "Smokin'", - "Snapping", - "Snappy", - "Snarling", - "Snow", - "Soaring", - "Space", - "Spiky", - "Spiny", - "Star", - "Steady", - "Steel", - "Stone", - "Storm", - "Striking", - "Strong", - "Stubborn", - "Sun", - "Super", - "Terrible", - "Thorny", - "Thunder", - "Top", - "Tough", - "Toxic", - "Tricky", - "Turquoise", - "Typhoon", - "Ultimate", - "Ultra", - "Ultramarine", - "Vengeful", - "Venom", - "Vermillion", - "Vicious", - "Victorious", - "Vigilant", - "Violent", - "Violet", - "War", - "Water", - "Whistling", - "White", - "Wicked", - "Wild", - "Wizard", - "Wrathful", - "Yellow", - "Young", - ) - ) - if adjective is None: - return animal.title() - return f"{adjective} {animal}".title() - - def random_nickname(self) -> str: - while True: - nickname = self._make_random_nickname() - if nickname not in self.used_nicknames: - self.used_nicknames.add(nickname) - return nickname diff --git a/game/coalition.py b/game/coalition.py deleted file mode 100644 index f8abad926..000000000 --- a/game/coalition.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from typing import Any, Optional, TYPE_CHECKING - -from faker import Faker - -from game.armedforces.armedforces import ArmedForces -from game.ato.airtaaskingorder import AirTaskingOrder -from game.campaignloader.defaultsquadronassigner import DefaultSquadronAssigner -from game.commander import TheaterCommander -from game.commander.missionscheduler import MissionScheduler -from game.income import Income -from game.navmesh import NavMesh -from game.orderedset import OrderedSet -from game.procurement import AircraftProcurementRequest, ProcurementAi -from game.profiling import MultiEventTracer, logged_duration -from game.squadrons import AirWing -from game.theater.bullseye import Bullseye -from game.theater.transitnetwork import TransitNetwork, TransitNetworkBuilder -from game.threatzones import ThreatZones -from game.transfers import PendingTransfers - -if TYPE_CHECKING: - from .campaignloader import CampaignAirWingConfig - from .data.doctrine import Doctrine - from .factions.faction import Faction - from .game import Game - from .lasercodes import LaserCodeRegistry - from .sim import GameUpdateEvents - - -class Coalition: - def __init__( - self, game: Game, faction: Faction, budget: float, player: bool - ) -> None: - self.game = game - self.player = player - self.faction = faction - self.budget = budget - self.ato = AirTaskingOrder() - self.transit_network = TransitNetwork() - self.procurement_requests: OrderedSet[AircraftProcurementRequest] = OrderedSet() - self.bullseye = Bullseye(self.game.point_in_world(0, 0)) - self.faker = Faker(self.faction.locales) - self.air_wing = AirWing(player, game, self.faction) - self.armed_forces = ArmedForces(self.faction) - self.transfers = PendingTransfers(game, player) - - # Late initialized because the two coalitions in the game are mutually - # dependent, so must be both constructed before this property can be set. - self._opponent: Optional[Coalition] = None - - # Volatile properties that are not persisted to the save file since they can be - # recomputed on load. Keeping this data out of the save file makes save compat - # breaks less frequent. Each of these properties has a non-underscore-prefixed - # @property that should be used for non-Optional access. - # - # All of these are late-initialized (whether via on_load or called later), but - # will be non-None after the game has finished loading. - self._threat_zone: Optional[ThreatZones] = None - self._navmesh: Optional[NavMesh] = None - self.on_load() - - @property - def doctrine(self) -> Doctrine: - return self.faction.doctrine - - @property - def coalition_id(self) -> int: - if self.player: - return 2 - return 1 - - @property - def country_name(self) -> str: - return self.faction.country - - @property - def opponent(self) -> Coalition: - assert self._opponent is not None - return self._opponent - - @property - def threat_zone(self) -> ThreatZones: - assert self._threat_zone is not None - return self._threat_zone - - @property - def nav_mesh(self) -> NavMesh: - assert self._navmesh is not None - return self._navmesh - - @property - def laser_code_registry(self) -> LaserCodeRegistry: - return self.game.laser_code_registry - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__.copy() - # Avoid persisting any volatile types that can be deterministically - # recomputed on load for the sake of save compatibility. - del state["_threat_zone"] - del state["_navmesh"] - del state["faker"] - return state - - def __setstate__(self, state: dict[str, Any]) -> None: - self.__dict__.update(state) - # Regenerate any state that was not persisted. - self.on_load() - - def on_load(self) -> None: - self.faker = Faker(self.faction.locales) - - def set_opponent(self, opponent: Coalition) -> None: - if self._opponent is not None: - raise RuntimeError("Double-initialization of Coalition.opponent") - self._opponent = opponent - - def configure_default_air_wing( - self, air_wing_config: CampaignAirWingConfig - ) -> None: - DefaultSquadronAssigner(air_wing_config, self.game, self).assign() - - def adjust_budget(self, amount: float) -> None: - self.budget += amount - - def compute_threat_zones(self, events: GameUpdateEvents) -> None: - self._threat_zone = ThreatZones.for_faction(self.game, self.player) - events.update_threat_zones(self.player, self._threat_zone) - - def compute_nav_meshes(self, events: GameUpdateEvents) -> None: - self._navmesh = NavMesh.from_threat_zones( - self.opponent.threat_zone, self.game.theater - ) - events.update_navmesh(self.player, self._navmesh) - - def update_transit_network(self) -> None: - self.transit_network = TransitNetworkBuilder( - self.game.theater, self.player - ).build() - - def set_bullseye(self, bullseye: Bullseye) -> None: - self.bullseye = bullseye - - def end_turn(self) -> None: - """Processes coalition-specific turn finalization. - - For more information on turn finalization in general, see the documentation for - `Game.finish_turn`. - """ - self.air_wing.end_turn() - self.budget += Income(self.game, self.player).total - - # Need to recompute before transfers and deliveries to account for captures. - # This happens in in initialize_turn as well, because cheating doesn't advance a - # turn but can capture bases so we need to recompute there as well. - self.update_transit_network() - - # Must happen *before* unit deliveries are handled, or else new units will spawn - # one hop ahead. ControlPoint.process_turn handles unit deliveries. The - # coalition-specific turn-end happens before the theater-wide turn-end, so this - # is handled correctly. - self.transfers.perform_transfers() - - def preinit_turn_0(self) -> None: - """Runs final Coalition initialization. - - Final initialization occurs before Game.initialize_turn runs for turn 0. - """ - self.air_wing.populate_for_turn_0() - - def initialize_turn(self, is_turn_0: bool) -> None: - """Processes coalition-specific turn initialization. - - For more information on turn initialization in general, see the documentation - for `Game.initialize_turn`. - """ - # Needs to happen *before* planning transfers so we don't cancel them. - self.ato.clear() - self.air_wing.reset() - self.refund_outstanding_orders() - self.procurement_requests.clear() - - with logged_duration("Transit network identification"): - self.update_transit_network() - with logged_duration("Procurement of airlift assets"): - self.transfers.order_airlift_assets() - with logged_duration("Transport planning"): - self.transfers.plan_transports(self.game.conditions.start_time) - - if not is_turn_0: - self.plan_missions(self.game.conditions.start_time) - self.plan_procurement() - - def refund_outstanding_orders(self) -> None: - # TODO: Split orders between air and ground units. - # This isn't quite right. If the player has ground purchases automated we should - # be refunding the ground units, and if they have air automated but not ground - # we should be refunding air units. - if self.player and not self.game.settings.automate_aircraft_reinforcements: - return - - for cp in self.game.theater.control_points_for(self.player): - cp.ground_unit_orders.refund_all(self) - for squadron in self.air_wing.iter_squadrons(): - squadron.refund_orders() - - def plan_missions(self, now: datetime) -> None: - color = "Blue" if self.player else "Red" - with MultiEventTracer() as tracer: - with tracer.trace(f"{color} mission planning"): - with tracer.trace(f"{color} mission identification"): - TheaterCommander(self.game, self.player).plan_missions(now, tracer) - with tracer.trace(f"{color} mission scheduling"): - MissionScheduler( - self, self.game.settings.desired_player_mission_duration - ).schedule_missions(now) - - def plan_procurement(self) -> None: - # The first turn needs to buy a *lot* of aircraft to fill CAPs, so it gets much - # more of the budget that turn. Otherwise budget (after repairs) is split evenly - # between air and ground. For the default starting budget of 2000 this gives 600 - # to ground forces and 1400 to aircraft. After that the budget will be spent - # proportionally based on how much is already invested. - - if self.player: - manage_runways = self.game.settings.automate_runway_repair - manage_front_line = self.game.settings.automate_front_line_reinforcements - manage_aircraft = self.game.settings.automate_aircraft_reinforcements - else: - manage_runways = True - manage_front_line = True - manage_aircraft = True - - self.budget = ProcurementAi( - self.game, - self.player, - self.faction, - manage_runways, - manage_front_line, - manage_aircraft, - ).spend_budget(self.budget) - - def add_procurement_request(self, request: AircraftProcurementRequest) -> None: - self.procurement_requests.add(request) diff --git a/game/commander/__init__.py b/game/commander/__init__.py deleted file mode 100644 index ac46c5ef8..000000000 --- a/game/commander/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .theatercommander import TheaterCommander diff --git a/game/commander/battlepositions.py b/game/commander/battlepositions.py deleted file mode 100644 index 5a232f100..000000000 --- a/game/commander/battlepositions.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from dataclasses import dataclass - -from game.theater import ControlPoint -from game.theater.theatergroundobject import VehicleGroupGroundObject -from game.utils import meters - - -@dataclass -class BattlePositions: - blocking_capture: list[VehicleGroupGroundObject] - defending_front_line: list[VehicleGroupGroundObject] - - @property - def in_priority_order(self) -> Iterator[VehicleGroupGroundObject]: - yield from self.blocking_capture - yield from self.defending_front_line - - def eliminate(self, battle_position: VehicleGroupGroundObject) -> None: - if battle_position in self.blocking_capture: - self.blocking_capture.remove(battle_position) - if battle_position in self.defending_front_line: - self.defending_front_line.remove(battle_position) - - def __contains__(self, item: VehicleGroupGroundObject) -> bool: - return item in self.in_priority_order - - @classmethod - def for_control_point(cls, control_point: ControlPoint) -> BattlePositions: - """Categorize battle position groups based on target priority. - - Any battle positions blocking base capture are the highest priority. - """ - blocking = [] - defending = [] - battle_positions = [ - tgo - for tgo in control_point.ground_objects - if isinstance(tgo, VehicleGroupGroundObject) and not tgo.is_dead - ] - for battle_position in battle_positions: - if ( - meters(battle_position.distance_to(control_point)) - < ControlPoint.CAPTURE_DISTANCE - ): - blocking.append(battle_position) - else: - defending.append(battle_position) - - return BattlePositions(blocking, defending) diff --git a/game/commander/missionproposals.py b/game/commander/missionproposals.py deleted file mode 100644 index 8749a76c9..000000000 --- a/game/commander/missionproposals.py +++ /dev/null @@ -1,58 +0,0 @@ -from dataclasses import field, dataclass -from enum import Enum, auto -from typing import Optional - -from game.theater import MissionTarget -from game.ato.flighttype import FlightType - - -class EscortType(Enum): - AirToAir = auto() - Sead = auto() - - -@dataclass(frozen=True) -class ProposedFlight: - """A flight outline proposed by the mission planner. - - Proposed flights haven't been assigned specific aircraft yet. They have only - a task, a required number of aircraft, and a maximum distance allowed - between the objective and the departure airfield. - """ - - #: The flight's role. - task: FlightType - - #: The number of aircraft required. - num_aircraft: int - - #: The type of threat this flight defends against if it is an escort. Escort - #: flights will be pruned if the rest of the package is not threatened by - #: the threat they defend against. If this flight is not an escort, this - #: field is None. - escort_type: Optional[EscortType] = field(default=None) - - def __str__(self) -> str: - return f"{self.task} {self.num_aircraft} ship" - - -@dataclass(frozen=True) -class ProposedMission: - """A mission outline proposed by the mission planner. - - Proposed missions haven't been assigned aircraft yet. They have only an - objective location and a list of proposed flights that are required for the - mission. - """ - - #: The mission objective. - location: MissionTarget - - #: The proposed flights that are required for the mission. - flights: list[ProposedFlight] - - asap: bool = field(default=False) - - def __str__(self) -> str: - flights = ", ".join([str(f) for f in self.flights]) - return f"{self.location.name}: {flights}" diff --git a/game/commander/missionscheduler.py b/game/commander/missionscheduler.py deleted file mode 100644 index fe3082193..000000000 --- a/game/commander/missionscheduler.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import annotations - -import logging -import random -from collections import defaultdict -from datetime import datetime, timedelta -from typing import Iterator, TYPE_CHECKING - -from game.ato.flighttype import FlightType -from game.ato.traveltime import TotEstimator -from game.theater import MissionTarget - -if TYPE_CHECKING: - from game.coalition import Coalition - - -class MissionScheduler: - def __init__(self, coalition: Coalition, desired_mission_length: timedelta) -> None: - self.coalition = coalition - self.desired_mission_length = desired_mission_length - - def schedule_missions(self, now: datetime) -> None: - """Identifies and plans mission for the turn.""" - - def start_time_generator( - count: int, earliest: int, latest: int, margin: int - ) -> Iterator[timedelta]: - interval = (latest - earliest) // count - for time in range(earliest, latest, interval): - error = random.randint(-margin, margin) - yield timedelta(seconds=max(0, time + error)) - - dca_types = { - FlightType.BARCAP, - FlightType.TARCAP, - } - - previous_cap_end_time: dict[MissionTarget, datetime] = defaultdict(now.replace) - non_dca_packages = [ - p for p in self.coalition.ato.packages if p.primary_task not in dca_types - ] - - start_time = start_time_generator( - count=len(non_dca_packages), - earliest=5 * 60, - latest=int(self.desired_mission_length.total_seconds()), - margin=5 * 60, - ) - for package in self.coalition.ato.packages: - tot = TotEstimator(package).earliest_tot(now) - if package.primary_task in dca_types: - previous_end_time = previous_cap_end_time[package.target] - if tot > previous_end_time: - # Can't get there exactly on time, so get there ASAP. This - # will typically only happen for the first CAP at each - # target. - package.time_over_target = tot - else: - package.time_over_target = previous_end_time - - departure_time = package.mission_departure_time - # Should be impossible for CAPs - if departure_time is None: - logging.error(f"Could not determine mission end time for {package}") - continue - previous_cap_end_time[package.target] = departure_time - elif package.auto_asap: - package.set_tot_asap(now) - else: - # But other packages should be spread out a bit. Note that take - # times are delayed, but all aircraft will become active at - # mission start. This makes it more worthwhile to attack enemy - # airfields to hit grounded aircraft, since they're more likely - # to be present. Runway and air started aircraft will be - # delayed until their takeoff time by AirConflictGenerator. - package.time_over_target = next(start_time) + tot diff --git a/game/commander/objectivefinder.py b/game/commander/objectivefinder.py deleted file mode 100644 index 2ba40f145..000000000 --- a/game/commander/objectivefinder.py +++ /dev/null @@ -1,272 +0,0 @@ -from __future__ import annotations - -import math -import operator -from collections.abc import Iterable, Iterator -from typing import TYPE_CHECKING, TypeVar - -from game.ato.closestairfields import ClosestAirfields, ObjectiveDistanceCache -from game.theater import ( - Airfield, - ControlPoint, - Fob, - FrontLine, - MissionTarget, - OffMapSpawn, -) -from game.theater.theatergroundobject import ( - BuildingGroundObject, - IadsBuildingGroundObject, - IadsGroundObject, - NavalGroundObject, -) -from game.utils import meters, nautical_miles - -if TYPE_CHECKING: - from game import Game - from game.transfers import CargoShip, Convoy - from game.threatzones import ThreatZones - -MissionTargetType = TypeVar("MissionTargetType", bound=MissionTarget) - - -class ObjectiveFinder: - """Identifies potential objectives for the mission planner.""" - - # TODO: Merge into doctrine. - AIRFIELD_THREAT_RANGE = nautical_miles(150) - SAM_THREAT_RANGE = nautical_miles(100) - - def __init__(self, game: Game, is_player: bool) -> None: - self.game = game - self.is_player = is_player - - def enemy_air_defenses(self) -> Iterator[IadsGroundObject]: - """Iterates over all enemy SAM sites.""" - for cp in self.enemy_control_points(): - for ground_object in cp.ground_objects: - if ground_object.is_dead: - continue - - if isinstance(ground_object, IadsGroundObject): - yield ground_object - - def enemy_ships(self) -> Iterator[NavalGroundObject]: - for cp in self.enemy_control_points(): - for ground_object in cp.ground_objects: - if not isinstance(ground_object, NavalGroundObject): - continue - - if ground_object.is_dead: - continue - - yield ground_object - - def threatening_ships(self) -> Iterator[NavalGroundObject]: - """Iterates over enemy ships near friendly control points. - - Groups are sorted by their closest proximity to any friendly control - point (airfield or fleet). - """ - return self._targets_by_range(self.enemy_ships()) - - def _targets_by_range( - self, targets: Iterable[MissionTargetType] - ) -> Iterator[MissionTargetType]: - target_ranges: list[tuple[MissionTargetType, float]] = [] - for target in targets: - ranges: list[float] = [] - for cp in self.friendly_control_points(): - ranges.append(target.distance_to(cp)) - target_ranges.append((target, min(ranges))) - - target_ranges = sorted(target_ranges, key=operator.itemgetter(1)) - for target, _range in target_ranges: - yield target - - def strike_targets(self) -> Iterator[BuildingGroundObject]: - """Iterates over enemy strike targets. - - Targets are sorted by their closest proximity to any friendly control - point (airfield or fleet). - """ - targets: list[tuple[BuildingGroundObject, float]] = [] - # Building objectives are made of several individual TGOs (one per - # building). - found_targets: set[str] = set() - for enemy_cp in self.enemy_control_points(): - for ground_object in enemy_cp.ground_objects: - # TODO: Reuse ground_object.mission_types. - # The mission types for ground objects are currently not - # accurate because we include things like strike and BAI for all - # targets since they have different planning behavior (waypoint - # generation is better for players with strike when the targets - # are stationary, AI behavior against weaker air defenses is - # better with BAI), so that's not a useful filter. Once we have - # better control over planning profiles and target dependent - # loadouts we can clean this up. - if not isinstance(ground_object, BuildingGroundObject): - # Other group types (like ships, SAMs, battle positions, etc) have better - # suited mission types like anti-ship, DEAD, and BAI. - continue - - if isinstance(enemy_cp, Fob) and ground_object.is_control_point: - # This is the FOB structure itself. Can't be repaired or - # targeted by the player, so shouldn't be targetable by the - # AI. - continue - - if isinstance( - ground_object, IadsBuildingGroundObject - ) and not self.game.lua_plugin_manager.is_plugin_enabled("skynetiads"): - # Prevent strike targets on IADS Buildings when skynet features - # are disabled as they do not serve any purpose - continue - - if ground_object.is_dead: - continue - if ground_object.name in found_targets: - continue - ranges: list[float] = [] - for friendly_cp in self.friendly_control_points(): - ranges.append(ground_object.distance_to(friendly_cp)) - targets.append((ground_object, min(ranges))) - found_targets.add(ground_object.name) - targets = sorted(targets, key=operator.itemgetter(1)) - for target, _range in targets: - yield target - - def front_lines(self) -> Iterator[FrontLine]: - """Iterates over all active front lines in the theater.""" - yield from self.game.theater.conflicts() - - def vulnerable_control_points(self) -> Iterator[ControlPoint]: - """Iterates over friendly CPs that are vulnerable to enemy CPs. - - Vulnerability is defined as any enemy CP within threat range of of the - CP. - """ - for cp in self.friendly_control_points(): - if isinstance(cp, OffMapSpawn): - # Off-map spawn locations don't need protection. - continue - airfields_in_proximity = self.closest_airfields_to(cp) - airfields_in_threat_range = ( - airfields_in_proximity.operational_airfields_within( - self.AIRFIELD_THREAT_RANGE - ) - ) - for airfield in airfields_in_threat_range: - if not airfield.is_friendly(self.is_player): - yield cp - break - - def oca_targets(self, min_aircraft: int) -> Iterator[ControlPoint]: - airfields = [] - for control_point in self.enemy_control_points(): - if not isinstance(control_point, Airfield): - continue - if control_point.allocated_aircraft().total_present >= min_aircraft: - airfields.append(control_point) - return self._targets_by_range(airfields) - - def convoys(self) -> Iterator[Convoy]: - for front_line in self.front_lines(): - yield from self.game.coalition_for( - self.is_player - ).transfers.convoys.travelling_to( - front_line.control_point_hostile_to(self.is_player) - ) - - def cargo_ships(self) -> Iterator[CargoShip]: - for front_line in self.front_lines(): - yield from self.game.coalition_for( - self.is_player - ).transfers.cargo_ships.travelling_to( - front_line.control_point_hostile_to(self.is_player) - ) - - def friendly_control_points(self) -> Iterator[ControlPoint]: - """Iterates over all friendly control points.""" - return ( - c for c in self.game.theater.controlpoints if c.is_friendly(self.is_player) - ) - - def farthest_friendly_control_point(self) -> ControlPoint: - """Finds the friendly control point that is farthest from any threats.""" - - def find_farthest( - control_points: Iterator[ControlPoint], - threat_zones: ThreatZones, - consider_off_map_spawn: bool, - ) -> ControlPoint | None: - farthest = None - max_distance = meters(0) - for cp in control_points: - if isinstance(cp, OffMapSpawn) and not consider_off_map_spawn: - continue - distance = threat_zones.distance_to_threat(cp.position) - if distance > max_distance: - farthest = cp - max_distance = distance - return farthest - - threat_zones = self.game.threat_zone_for(not self.is_player) - - farthest = find_farthest( - self.friendly_control_points(), threat_zones, consider_off_map_spawn=False - ) - - # If there are only off-map spawn control points, fall back to the farthest amongst off map spawn points - if farthest is None: - farthest = find_farthest( - self.friendly_control_points(), - threat_zones, - consider_off_map_spawn=True, - ) - - if farthest is None: - raise RuntimeError("Found no friendly control points. You probably lost.") - return farthest - - def preferred_theater_refueling_control_point(self) -> ControlPoint | None: - """Finds the friendly control point that is closest to any threats.""" - threat_zones = self.game.threat_zone_for(not self.is_player) - - closest = None - min_distance = meters(math.inf) - for cp in self.friendly_control_points(): - if isinstance(cp, OffMapSpawn) or cp.is_fleet: - continue - distance = threat_zones.distance_to_threat(cp.position) - if distance < min_distance: - closest = cp - min_distance = distance - - return closest - - def enemy_control_points(self) -> Iterator[ControlPoint]: - """Iterates over all enemy control points.""" - return ( - c - for c in self.game.theater.controlpoints - if not c.is_friendly(self.is_player) - ) - - def prioritized_unisolated_points(self) -> list[ControlPoint]: - prioritized = [] - capturable_later = [] - for cp in self.game.theater.control_points_for(not self.is_player): - if cp.is_isolated: - continue - if cp.has_active_frontline: - prioritized.append(cp) - else: - capturable_later.append(cp) - prioritized.extend(self._targets_by_range(capturable_later)) - return prioritized - - @staticmethod - def closest_airfields_to(location: MissionTarget) -> ClosestAirfields: - """Returns the closest airfields to the given location.""" - return ObjectiveDistanceCache.get_closest_airfields(location) diff --git a/game/commander/packagebuilder.py b/game/commander/packagebuilder.py deleted file mode 100644 index 2aea54caf..000000000 --- a/game/commander/packagebuilder.py +++ /dev/null @@ -1,103 +0,0 @@ -from __future__ import annotations - -from typing import Optional, TYPE_CHECKING - -from game.theater import ControlPoint, MissionTarget, OffMapSpawn -from game.utils import nautical_miles -from ..ato.flight import Flight -from ..ato.package import Package -from ..ato.starttype import StartType -from ..db.database import Database - -if TYPE_CHECKING: - from game.ato.closestairfields import ClosestAirfields - from game.dcs.aircrafttype import AircraftType - from game.lasercodes import LaserCodeRegistry - from game.squadrons.airwing import AirWing - from .missionproposals import ProposedFlight - - -class PackageBuilder: - """Builds a Package for the flights it receives.""" - - def __init__( - self, - location: MissionTarget, - closest_airfields: ClosestAirfields, - air_wing: AirWing, - laser_code_registry: LaserCodeRegistry, - flight_db: Database[Flight], - is_player: bool, - package_country: str, - start_type: StartType, - asap: bool, - ) -> None: - self.closest_airfields = closest_airfields - self.is_player = is_player - self.package_country = package_country - self.package = Package(location, flight_db, auto_asap=asap) - self.air_wing = air_wing - self.laser_code_registry = laser_code_registry - self.start_type = start_type - - def plan_flight(self, plan: ProposedFlight) -> bool: - """Allocates aircraft for the given flight and adds them to the package. - - If no suitable aircraft are available, False is returned. If the failed - flight was critical and the rest of the mission will be scrubbed, the - caller should return any previously planned flights to the inventory - using release_planned_aircraft. - """ - squadron = self.air_wing.best_squadron_for( - self.package.target, plan.task, plan.num_aircraft, this_turn=True - ) - if squadron is None: - return False - start_type = squadron.location.required_aircraft_start_type - if start_type is None: - start_type = self.start_type - - flight = Flight( - self.package, - self.package_country, - squadron, - plan.num_aircraft, - plan.task, - start_type, - divert=self.find_divert_field(squadron.aircraft, squadron.location), - ) - for member in flight.iter_members(): - if member.is_player: - member.assign_tgp_laser_code( - self.laser_code_registry.alloc_laser_code() - ) - self.package.add_flight(flight) - return True - - def find_divert_field( - self, aircraft: AircraftType, arrival: ControlPoint - ) -> Optional[ControlPoint]: - divert_limit = nautical_miles(150) - for airfield in self.closest_airfields.operational_airfields_within( - divert_limit - ): - if airfield.captured != self.is_player: - continue - if airfield == arrival: - continue - if not airfield.can_operate(aircraft): - continue - if isinstance(airfield, OffMapSpawn): - continue - return airfield - return None - - def build(self) -> Package: - """Returns the built package.""" - return self.package - - def release_planned_aircraft(self) -> None: - """Returns any planned flights to the inventory.""" - flights = list(self.package.flights) - for flight in flights: - self.package.remove_flight(flight) diff --git a/game/commander/packagefulfiller.py b/game/commander/packagefulfiller.py deleted file mode 100644 index 7e66eafa7..000000000 --- a/game/commander/packagefulfiller.py +++ /dev/null @@ -1,229 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from datetime import datetime -from typing import Dict, Iterable, Optional, Set, TYPE_CHECKING - -from game.ato.airtaaskingorder import AirTaskingOrder -from game.ato.closestairfields import ObjectiveDistanceCache -from game.ato.flighttype import FlightType -from game.ato.package import Package -from game.commander.missionproposals import EscortType, ProposedFlight, ProposedMission -from game.commander.packagebuilder import PackageBuilder -from game.data.doctrine import Doctrine -from game.db import Database -from game.procurement import AircraftProcurementRequest -from game.profiling import MultiEventTracer -from game.settings import Settings -from game.squadrons import AirWing -from game.theater import ConflictTheater -from game.threatzones import ThreatZones - -if TYPE_CHECKING: - from game.ato import Flight - from game.coalition import Coalition - - -class PackageFulfiller: - """Responsible for package aircraft allocation and flight plan layout.""" - - def __init__( - self, - coalition: Coalition, - theater: ConflictTheater, - flight_db: Database[Flight], - settings: Settings, - ) -> None: - self.coalition = coalition - self.theater = theater - self.flight_db = flight_db - self.player_missions_asap = settings.auto_ato_player_missions_asap - self.default_start_type = settings.default_start_type - - @property - def is_player(self) -> bool: - return self.coalition.player - - @property - def ato(self) -> AirTaskingOrder: - return self.coalition.ato - - @property - def air_wing(self) -> AirWing: - return self.coalition.air_wing - - @property - def doctrine(self) -> Doctrine: - return self.coalition.doctrine - - @property - def threat_zones(self) -> ThreatZones: - return self.coalition.opponent.threat_zone - - def add_procurement_request(self, request: AircraftProcurementRequest) -> None: - self.coalition.add_procurement_request(request) - - def air_wing_can_plan(self, mission_type: FlightType) -> bool: - """Returns True if it is possible for the air wing to plan this mission type. - - Not all mission types can be fulfilled by all air wings. Many factions do not - have AEW&C aircraft, so they will never be able to plan those missions. It's - also possible for the player to exclude mission types from their squadron - designs. - """ - return self.air_wing.can_auto_plan(mission_type) - - def plan_flight( - self, - mission: ProposedMission, - flight: ProposedFlight, - builder: PackageBuilder, - missing_types: Set[FlightType], - purchase_multiplier: int, - ) -> None: - if not builder.plan_flight(flight): - missing_types.add(flight.task) - purchase_order = AircraftProcurementRequest( - near=mission.location, - task_capability=flight.task, - number=flight.num_aircraft * purchase_multiplier, - ) - # Reserves are planned for critical missions, so prioritize those orders - # over aircraft needed for non-critical missions. - self.add_procurement_request(purchase_order) - - def scrub_mission_missing_aircraft( - self, - mission: ProposedMission, - builder: PackageBuilder, - missing_types: Set[FlightType], - not_attempted: Iterable[ProposedFlight], - purchase_multiplier: int, - ) -> None: - # Try to plan the rest of the mission just so we can count the missing - # types to buy. - for flight in not_attempted: - self.plan_flight( - mission, flight, builder, missing_types, purchase_multiplier - ) - - missing_types_str = ", ".join(sorted([t.name for t in missing_types])) - builder.release_planned_aircraft() - color = "Blue" if self.is_player else "Red" - logging.debug( - f"{color}: not enough aircraft in range for {mission.location.name} " - f"capable of: {missing_types_str}" - ) - - def check_needed_escorts(self, builder: PackageBuilder) -> Dict[EscortType, bool]: - threats = defaultdict(bool) - for flight in builder.package.flights: - if self.threat_zones.waypoints_threatened_by_aircraft( - flight.flight_plan.escorted_waypoints() - ): - threats[EscortType.AirToAir] = True - if self.threat_zones.waypoints_threatened_by_radar_sam( - list(flight.flight_plan.escorted_waypoints()) - ): - threats[EscortType.Sead] = True - return threats - - def plan_mission( - self, - mission: ProposedMission, - purchase_multiplier: int, - now: datetime, - tracer: MultiEventTracer, - ) -> Optional[Package]: - """Allocates aircraft for a proposed mission and adds it to the ATO.""" - builder = PackageBuilder( - mission.location, - ObjectiveDistanceCache.get_closest_airfields(mission.location), - self.air_wing, - self.coalition.laser_code_registry, - self.flight_db, - self.is_player, - self.coalition.country_name, - self.default_start_type, - mission.asap, - ) - - # Attempt to plan all the main elements of the mission first. Escorts - # will be planned separately so we can prune escorts for packages that - # are not expected to encounter that type of threat. - missing_types: Set[FlightType] = set() - escorts = [] - for proposed_flight in mission.flights: - if not self.air_wing_can_plan(proposed_flight.task): - # This air wing can never plan this mission type because they do not - # have compatible aircraft or squadrons. Skip fulfillment so that we - # don't place the purchase request. - continue - if proposed_flight.escort_type is not None: - # Escorts are planned after the primary elements of the package. - # If the package does not need escorts they may be pruned. - escorts.append(proposed_flight) - continue - with tracer.trace("Flight planning"): - self.plan_flight( - mission, - proposed_flight, - builder, - missing_types, - purchase_multiplier, - ) - - if missing_types: - self.scrub_mission_missing_aircraft( - mission, builder, missing_types, escorts, purchase_multiplier - ) - return None - - if not builder.package.flights: - # The non-escort part of this mission is unplannable by this faction. Scrub - # the mission and do not attempt planning escorts because there's no reason - # to buy them because this mission will never be planned. - return None - - # Create flight plans for the main flights of the package so we can - # determine threats. This is done *after* creating all of the flights - # rather than as each flight is added because the flight plan for - # flights that will rendezvous with their package will be affected by - # the other flights in the package. Escorts will not be able to - # contribute to this. - for flight in builder.package.flights: - with tracer.trace("Flight plan population"): - flight.recreate_flight_plan() - - needed_escorts = self.check_needed_escorts(builder) - for escort in escorts: - # This list was generated from the not None set, so this should be - # impossible. - assert escort.escort_type is not None - if needed_escorts[escort.escort_type]: - with tracer.trace("Flight planning"): - self.plan_flight( - mission, escort, builder, missing_types, purchase_multiplier - ) - - # Check again for unavailable aircraft. If the escort was required and - # none were found, scrub the mission. - if missing_types: - self.scrub_mission_missing_aircraft( - mission, builder, missing_types, escorts, purchase_multiplier - ) - return None - - package = builder.build() - # Add flight plans for escorts. - for flight in package.flights: - if not flight.flight_plan.waypoints: - with tracer.trace("Flight plan population"): - flight.recreate_flight_plan() - - if package.has_players and self.player_missions_asap: - package.auto_asap = True - package.set_tot_asap(now) - - return package diff --git a/game/commander/tasks/compound/aewcsupport.py b/game/commander/tasks/compound/aewcsupport.py deleted file mode 100644 index d27ffb4b1..000000000 --- a/game/commander/tasks/compound/aewcsupport.py +++ /dev/null @@ -1,11 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.aewc import PlanAewc -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class PlanAewcSupport(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for target in state.aewc_targets: - yield [PlanAewc(target)] diff --git a/game/commander/tasks/compound/attackairinfrastructure.py b/game/commander/tasks/compound/attackairinfrastructure.py deleted file mode 100644 index 9f6040130..000000000 --- a/game/commander/tasks/compound/attackairinfrastructure.py +++ /dev/null @@ -1,15 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.primitive.oca import PlanOcaStrike -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -@dataclass(frozen=True) -class AttackAirInfrastructure(CompoundTask[TheaterState]): - aircraft_cold_start: bool - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for battle_position in state.oca_targets: - yield [PlanOcaStrike(battle_position, self.aircraft_cold_start)] diff --git a/game/commander/tasks/compound/attackbattlepositions.py b/game/commander/tasks/compound/attackbattlepositions.py deleted file mode 100644 index 2286a3415..000000000 --- a/game/commander/tasks/compound/attackbattlepositions.py +++ /dev/null @@ -1,12 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.bai import PlanBai -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class AttackBattlePositions(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for battle_positions in state.enemy_battle_positions.values(): - for battle_position in battle_positions.in_priority_order: - yield [PlanBai(battle_position)] diff --git a/game/commander/tasks/compound/attackbuildings.py b/game/commander/tasks/compound/attackbuildings.py deleted file mode 100644 index d00736fb6..000000000 --- a/game/commander/tasks/compound/attackbuildings.py +++ /dev/null @@ -1,15 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.strike import PlanStrike -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class AttackBuildings(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for building in state.strike_targets: - # Ammo depots are targeted based on the needs of the front line by - # ReduceEnemyFrontLineCapacity. No reason to target them before that front - # line is active. - if not building.is_ammo_depot: - yield [PlanStrike(building)] diff --git a/game/commander/tasks/compound/capturebase.py b/game/commander/tasks/compound/capturebase.py deleted file mode 100644 index 378cb13e5..000000000 --- a/game/commander/tasks/compound/capturebase.py +++ /dev/null @@ -1,51 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.compound.destroyenemygroundunits import ( - DestroyEnemyGroundUnits, -) -from game.commander.tasks.compound.reduceenemyfrontlinecapacity import ( - ReduceEnemyFrontLineCapacity, -) -from game.commander.tasks.primitive.breakthroughattack import BreakthroughAttack -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method -from game.theater import ControlPoint, FrontLine - - -@dataclass(frozen=True) -class CaptureBase(CompoundTask[TheaterState]): - front_line: FrontLine - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - yield [BreakthroughAttack(self.front_line, state.context.coalition.player)] - yield [DestroyEnemyGroundUnits(self.front_line)] - if self.worth_destroying_ammo_depots(state): - yield [ReduceEnemyFrontLineCapacity(self.enemy_cp(state))] - - def enemy_cp(self, state: TheaterState) -> ControlPoint: - return self.front_line.control_point_hostile_to(state.context.coalition.player) - - def units_deployable(self, state: TheaterState, player: bool) -> int: - cp = self.front_line.control_point_friendly_to(player) - ammo_depots = list(state.ammo_dumps_at(cp)) - return cp.deployable_front_line_units_with(len(ammo_depots)) - - def unit_cap(self, state: TheaterState, player: bool) -> int: - cp = self.front_line.control_point_friendly_to(player) - ammo_depots = list(state.ammo_dumps_at(cp)) - return cp.front_line_capacity_with(len(ammo_depots)) - - def enemy_has_ammo_dumps(self, state: TheaterState) -> bool: - return bool(state.ammo_dumps_at(self.enemy_cp(state))) - - def worth_destroying_ammo_depots(self, state: TheaterState) -> bool: - if not self.enemy_has_ammo_dumps(state): - return False - - friendly_cap = self.unit_cap(state, state.context.coalition.player) - enemy_deployable = self.units_deployable(state, state.context.coalition.player) - - # If the enemy can currently deploy 50% more units than we possibly could, it's - # worth killing an ammo depot. - return enemy_deployable / friendly_cap > 1.5 diff --git a/game/commander/tasks/compound/capturebases.py b/game/commander/tasks/compound/capturebases.py deleted file mode 100644 index db9068caf..000000000 --- a/game/commander/tasks/compound/capturebases.py +++ /dev/null @@ -1,13 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.compound.capturebase import CaptureBase -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -@dataclass(frozen=True) -class CaptureBases(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for front in state.active_front_lines: - yield [CaptureBase(front)] diff --git a/game/commander/tasks/compound/defendbase.py b/game/commander/tasks/compound/defendbase.py deleted file mode 100644 index ff1e1dcb8..000000000 --- a/game/commander/tasks/compound/defendbase.py +++ /dev/null @@ -1,19 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.primitive.cas import PlanCas -from game.commander.tasks.primitive.defensivestance import DefensiveStance -from game.commander.tasks.primitive.retreatstance import RetreatStance -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method -from game.theater import FrontLine - - -@dataclass(frozen=True) -class DefendBase(CompoundTask[TheaterState]): - front_line: FrontLine - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - yield [DefensiveStance(self.front_line, state.context.coalition.player)] - yield [RetreatStance(self.front_line, state.context.coalition.player)] - yield [PlanCas(self.front_line)] diff --git a/game/commander/tasks/compound/defendbases.py b/game/commander/tasks/compound/defendbases.py deleted file mode 100644 index 87f14d685..000000000 --- a/game/commander/tasks/compound/defendbases.py +++ /dev/null @@ -1,13 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.compound.defendbase import DefendBase -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -@dataclass(frozen=True) -class DefendBases(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for front in state.active_front_lines: - yield [DefendBase(front)] diff --git a/game/commander/tasks/compound/degradeiads.py b/game/commander/tasks/compound/degradeiads.py deleted file mode 100644 index a40ae8e9f..000000000 --- a/game/commander/tasks/compound/degradeiads.py +++ /dev/null @@ -1,24 +0,0 @@ -from collections.abc import Iterator -from typing import Union - -from game.commander.tasks.primitive.antiship import PlanAntiShip -from game.commander.tasks.primitive.dead import PlanDead -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method -from game.theater.theatergroundobject import IadsGroundObject, NavalGroundObject - - -class DegradeIads(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for air_defense in state.threatening_air_defenses: - yield [self.plan_against(air_defense)] - for detector in state.detecting_air_defenses: - yield [self.plan_against(detector)] - - @staticmethod - def plan_against( - target: Union[IadsGroundObject, NavalGroundObject] - ) -> Union[PlanDead, PlanAntiShip]: - if isinstance(target, IadsGroundObject): - return PlanDead(target) - return PlanAntiShip(target) diff --git a/game/commander/tasks/compound/destroyenemygroundunits.py b/game/commander/tasks/compound/destroyenemygroundunits.py deleted file mode 100644 index fe54b57c1..000000000 --- a/game/commander/tasks/compound/destroyenemygroundunits.py +++ /dev/null @@ -1,19 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.primitive.aggressiveattack import AggressiveAttack -from game.commander.tasks.primitive.cas import PlanCas -from game.commander.tasks.primitive.eliminationattack import EliminationAttack -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method -from game.theater import FrontLine - - -@dataclass(frozen=True) -class DestroyEnemyGroundUnits(CompoundTask[TheaterState]): - front_line: FrontLine - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - yield [EliminationAttack(self.front_line, state.context.coalition.player)] - yield [AggressiveAttack(self.front_line, state.context.coalition.player)] - yield [PlanCas(self.front_line)] diff --git a/game/commander/tasks/compound/frontlinedefense.py b/game/commander/tasks/compound/frontlinedefense.py deleted file mode 100644 index 368558627..000000000 --- a/game/commander/tasks/compound/frontlinedefense.py +++ /dev/null @@ -1,11 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.cas import PlanCas -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class FrontLineDefense(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for front_line in state.vulnerable_front_lines: - yield [PlanCas(front_line)] diff --git a/game/commander/tasks/compound/interdictreinforcements.py b/game/commander/tasks/compound/interdictreinforcements.py deleted file mode 100644 index d5b127ad5..000000000 --- a/game/commander/tasks/compound/interdictreinforcements.py +++ /dev/null @@ -1,27 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.antishipping import PlanAntiShipping -from game.commander.tasks.primitive.convoyinterdiction import PlanConvoyInterdiction -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class InterdictReinforcements(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - # These will only rarely get planned. When a convoy is travelling multiple legs, - # they're targetable after the first leg. The reason for this is that - # procurement happens *after* mission planning so that the missions that could - # not be filled will guide the procurement process. Procurement is the stage - # that convoys are created (because they're created to move ground units that - # were just purchased), so we haven't created any yet. Any incomplete transfers - # from the previous turn (multi-leg journeys) will still be present though so - # they can be targeted. - # - # Even after this is fixed, the player's convoys that were created through the - # UI will never be targeted on the first turn of their journey because the AI - # stops planning after the start of the turn. We could potentially fix this by - # moving opfor mission planning until the takeoff button is pushed. - for convoy in state.enemy_convoys: - yield [PlanConvoyInterdiction(convoy)] - for ship in state.enemy_shipping: - yield [PlanAntiShipping(ship)] diff --git a/game/commander/tasks/compound/nextaction.py b/game/commander/tasks/compound/nextaction.py deleted file mode 100644 index 56c6bad23..000000000 --- a/game/commander/tasks/compound/nextaction.py +++ /dev/null @@ -1,34 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.compound.attackairinfrastructure import ( - AttackAirInfrastructure, -) -from game.commander.tasks.compound.attackbuildings import AttackBuildings -from game.commander.tasks.compound.attackbattlepositions import AttackBattlePositions -from game.commander.tasks.compound.capturebases import CaptureBases -from game.commander.tasks.compound.defendbases import DefendBases -from game.commander.tasks.compound.degradeiads import DegradeIads -from game.commander.tasks.compound.interdictreinforcements import ( - InterdictReinforcements, -) -from game.commander.tasks.compound.protectairspace import ProtectAirSpace -from game.commander.tasks.compound.theatersupport import TheaterSupport -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -@dataclass(frozen=True) -class PlanNextAction(CompoundTask[TheaterState]): - aircraft_cold_start: bool - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - yield [TheaterSupport()] - yield [ProtectAirSpace()] - yield [CaptureBases()] - yield [DefendBases()] - yield [InterdictReinforcements()] - yield [AttackBattlePositions()] - yield [AttackAirInfrastructure(self.aircraft_cold_start)] - yield [AttackBuildings()] - yield [DegradeIads()] diff --git a/game/commander/tasks/compound/protectairspace.py b/game/commander/tasks/compound/protectairspace.py deleted file mode 100644 index b5727259a..000000000 --- a/game/commander/tasks/compound/protectairspace.py +++ /dev/null @@ -1,12 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.barcap import PlanBarcap -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class ProtectAirSpace(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for cp, needed in state.barcaps_needed.items(): - if needed > 0: - yield [PlanBarcap(cp, needed)] diff --git a/game/commander/tasks/compound/reduceenemyfrontlinecapacity.py b/game/commander/tasks/compound/reduceenemyfrontlinecapacity.py deleted file mode 100644 index 22d3e728e..000000000 --- a/game/commander/tasks/compound/reduceenemyfrontlinecapacity.py +++ /dev/null @@ -1,16 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.primitive.strike import PlanStrike -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method -from game.theater import ControlPoint - - -@dataclass(frozen=True) -class ReduceEnemyFrontLineCapacity(CompoundTask[TheaterState]): - control_point: ControlPoint - - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for ammo_dump in state.ammo_dumps_at(self.control_point): - yield [PlanStrike(ammo_dump)] diff --git a/game/commander/tasks/compound/refuelingsupport.py b/game/commander/tasks/compound/refuelingsupport.py deleted file mode 100644 index e1f266035..000000000 --- a/game/commander/tasks/compound/refuelingsupport.py +++ /dev/null @@ -1,11 +0,0 @@ -from collections.abc import Iterator - -from game.commander.tasks.primitive.refueling import PlanRefueling -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -class PlanRefuelingSupport(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - for target in state.refueling_targets: - yield [PlanRefueling(target)] diff --git a/game/commander/tasks/compound/theatersupport.py b/game/commander/tasks/compound/theatersupport.py deleted file mode 100644 index 94f8e040a..000000000 --- a/game/commander/tasks/compound/theatersupport.py +++ /dev/null @@ -1,14 +0,0 @@ -from collections.abc import Iterator -from dataclasses import dataclass - -from game.commander.tasks.compound.aewcsupport import PlanAewcSupport -from game.commander.tasks.compound.refuelingsupport import PlanRefuelingSupport -from game.commander.theaterstate import TheaterState -from game.htn import CompoundTask, Method - - -@dataclass(frozen=True) -class TheaterSupport(CompoundTask[TheaterState]): - def each_valid_method(self, state: TheaterState) -> Iterator[Method[TheaterState]]: - yield [PlanAewcSupport()] - yield [PlanRefuelingSupport()] diff --git a/game/commander/tasks/frontlinestancetask.py b/game/commander/tasks/frontlinestancetask.py deleted file mode 100644 index 0eaa6aa4a..000000000 --- a/game/commander/tasks/frontlinestancetask.py +++ /dev/null @@ -1,77 +0,0 @@ -from __future__ import annotations - -import math -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING - -from game.commander.tasks.theatercommandertask import TheaterCommanderTask -from game.commander.theaterstate import TheaterState -from game.ground_forces.combat_stance import CombatStance -from game.theater import FrontLine - -if TYPE_CHECKING: - from game.coalition import Coalition - - -class FrontLineStanceTask(TheaterCommanderTask, ABC): - def __init__(self, front_line: FrontLine, player: bool) -> None: - self.front_line = front_line - self.friendly_cp = self.front_line.control_point_friendly_to(player) - self.enemy_cp = self.front_line.control_point_hostile_to(player) - - @property - @abstractmethod - def stance(self) -> CombatStance: - ... - - @staticmethod - def management_allowed(state: TheaterState) -> bool: - return ( - not state.context.coalition.player - or state.context.settings.automate_front_line_stance - ) - - def better_stance_already_set(self, state: TheaterState) -> bool: - current_stance = state.front_line_stances[self.front_line] - if current_stance is None: - return False - preference = ( - CombatStance.RETREAT, - CombatStance.DEFENSIVE, - CombatStance.AMBUSH, - CombatStance.AGGRESSIVE, - CombatStance.ELIMINATION, - CombatStance.BREAKTHROUGH, - ) - current_rating = preference.index(current_stance) - new_rating = preference.index(self.stance) - return current_rating >= new_rating - - @property - @abstractmethod - def have_sufficient_front_line_advantage(self) -> bool: - ... - - @property - def ground_force_balance(self) -> float: - # TODO: Planned CAS missions should reduce the expected opposing force size. - friendly_forces = self.friendly_cp.deployable_front_line_units - enemy_forces = self.enemy_cp.deployable_front_line_units - if enemy_forces == 0: - return math.inf - return friendly_forces / enemy_forces - - def preconditions_met(self, state: TheaterState) -> bool: - if not self.management_allowed(state): - return False - if self.better_stance_already_set(state): - return False - if self.friendly_cp.deployable_front_line_units == 0: - return False - return self.have_sufficient_front_line_advantage - - def apply_effects(self, state: TheaterState) -> None: - state.front_line_stances[self.front_line] = self.stance - - def execute(self, coalition: Coalition) -> None: - self.friendly_cp.stances[self.enemy_cp.id] = self.stance diff --git a/game/commander/tasks/packageplanningtask.py b/game/commander/tasks/packageplanningtask.py deleted file mode 100644 index 36b11680c..000000000 --- a/game/commander/tasks/packageplanningtask.py +++ /dev/null @@ -1,176 +0,0 @@ -from __future__ import annotations - -import itertools -import operator -from abc import abstractmethod -from dataclasses import dataclass, field -from enum import IntEnum, auto, unique -from typing import Generic, Iterator, Optional, TYPE_CHECKING, TypeVar, Union - -from game.ato.flighttype import FlightType -from game.ato.package import Package -from game.commander.missionproposals import EscortType, ProposedFlight, ProposedMission -from game.commander.packagefulfiller import PackageFulfiller -from game.commander.tasks.theatercommandertask import TheaterCommanderTask -from game.commander.theaterstate import TheaterState -from game.settings import AutoAtoBehavior -from game.theater import MissionTarget -from game.theater.theatergroundobject import IadsGroundObject, NavalGroundObject -from game.utils import Distance, meters - -if TYPE_CHECKING: - from game.coalition import Coalition - -MissionTargetT = TypeVar("MissionTargetT", bound=MissionTarget) - - -@unique -class RangeType(IntEnum): - Detection = auto() - Threat = auto() - - -# TODO: Refactor so that we don't need to call up to the mission planner. -@dataclass -class PackagePlanningTask(TheaterCommanderTask, Generic[MissionTargetT]): - target: MissionTargetT - flights: list[ProposedFlight] = field(init=False) - package: Optional[Package] = field(init=False, default=None) - - def __post_init__(self) -> None: - self.flights = [] - - def preconditions_met(self, state: TheaterState) -> bool: - if ( - state.context.coalition.player - and state.context.settings.auto_ato_behavior is AutoAtoBehavior.Disabled - ): - return False - return self.fulfill_mission(state) - - def execute(self, coalition: Coalition) -> None: - if self.package is None: - raise RuntimeError("Attempted to execute failed package planning task") - coalition.ato.add_package(self.package) - - @abstractmethod - def propose_flights(self) -> None: - ... - - def propose_flight( - self, - task: FlightType, - num_aircraft: int, - escort_type: Optional[EscortType] = None, - ) -> None: - self.flights.append(ProposedFlight(task, num_aircraft, escort_type)) - - @property - def asap(self) -> bool: - return False - - @property - def purchase_multiplier(self) -> int: - """The multiplier for aircraft quantity when missions could not be fulfilled. - - For missions that do not schedule in rounds like BARCAPs do, this should be one - to ensure that the we only purchase enough aircraft to plan the mission once. - - For missions that repeat within the same turn, however, we may need to buy for - the same mission more than once. If three rounds of BARCAP still need to be - fulfilled, this would return 3, and we'd triplicate the purchase order. - - There is a small misbehavior here that's not symptomatic for our current mission - planning: multi-round, multi-flight packages will only purchase multiple sets of - aircraft for whatever is unavailable for the *first* failed package. For - example, if we extend this to CAS and have no CAS aircraft but enough TARCAP - aircraft for one round, we'll order CAS for every round but will not order any - TARCAP aircraft, since we can't know that TARCAP aircraft are needed until we - attempt to plan the second mission *without returning the first round aircraft*. - """ - return 1 - - def fulfill_mission(self, state: TheaterState) -> bool: - color = "blue" if state.context.coalition.player else "red" - self.propose_flights() - fulfiller = PackageFulfiller( - state.context.coalition, - state.context.theater, - state.context.game_db.flights, - state.context.settings, - ) - with state.context.tracer.trace(f"{color} {self.flights[0].task} planning"): - self.package = fulfiller.plan_mission( - ProposedMission(self.target, self.flights), - self.purchase_multiplier, - state.context.now, - state.context.tracer, - ) - return self.package is not None - - def propose_common_escorts(self) -> None: - self.propose_flight(FlightType.SEAD_ESCORT, 2, EscortType.Sead) - self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir) - - def iter_iads_ranges( - self, state: TheaterState, range_type: RangeType - ) -> Iterator[Union[IadsGroundObject, NavalGroundObject]]: - target_ranges: list[ - tuple[Union[IadsGroundObject, NavalGroundObject], Distance] - ] = [] - all_iads: Iterator[ - Union[IadsGroundObject, NavalGroundObject] - ] = itertools.chain(state.enemy_air_defenses, state.enemy_ships) - for target in all_iads: - distance = meters(target.distance_to(self.target)) - if range_type is RangeType.Detection: - target_range = target.max_detection_range() - elif range_type is RangeType.Threat: - target_range = target.max_threat_range() - else: - raise ValueError(f"Unknown RangeType: {range_type}") - if not target_range: - continue - - # IADS out of range of our target area will have a positive - # distance_to_threat and should be pruned. The rest have a decreasing - # distance_to_threat as overlap increases. The most negative distance has - # the greatest coverage of the target and should be treated as the highest - # priority threat. - distance_to_threat = distance - target_range - if distance_to_threat > meters(0): - continue - target_ranges.append((target, distance_to_threat)) - - # TODO: Prioritize IADS by vulnerability? - target_ranges = sorted(target_ranges, key=operator.itemgetter(1)) - for target, _range in target_ranges: - yield target - - def iter_detecting_iads( - self, state: TheaterState - ) -> Iterator[Union[IadsGroundObject, NavalGroundObject]]: - return self.iter_iads_ranges(state, RangeType.Detection) - - def iter_iads_threats( - self, state: TheaterState - ) -> Iterator[Union[IadsGroundObject, NavalGroundObject]]: - return self.iter_iads_ranges(state, RangeType.Threat) - - def target_area_preconditions_met( - self, state: TheaterState, ignore_iads: bool = False - ) -> bool: - """Checks if the target area has been cleared of threats.""" - threatened = False - - # Non-blocking, but analyzed so we can pick detectors worth eliminating. - for detector in self.iter_detecting_iads(state): - if detector not in state.detecting_air_defenses: - state.detecting_air_defenses.append(detector) - - if not ignore_iads: - for iads_threat in self.iter_iads_threats(state): - threatened = True - if iads_threat not in state.threatening_air_defenses: - state.threatening_air_defenses.append(iads_threat) - return not threatened diff --git a/game/commander/tasks/primitive/aewc.py b/game/commander/tasks/primitive/aewc.py deleted file mode 100644 index 3811dd447..000000000 --- a/game/commander/tasks/primitive/aewc.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater import MissionTarget -from game.ato.flighttype import FlightType - - -@dataclass -class PlanAewc(PackagePlanningTask[MissionTarget]): - def preconditions_met(self, state: TheaterState) -> bool: - if not super().preconditions_met(state): - return False - return self.target in state.aewc_targets - - def apply_effects(self, state: TheaterState) -> None: - state.aewc_targets.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.AEWC, 1) - - @property - def asap(self) -> bool: - # Supports all the early CAP flights, so should be in the air ASAP. - return True diff --git a/game/commander/tasks/primitive/aggressiveattack.py b/game/commander/tasks/primitive/aggressiveattack.py deleted file mode 100644 index 255d22daf..000000000 --- a/game/commander/tasks/primitive/aggressiveattack.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from game.commander.tasks.frontlinestancetask import FrontLineStanceTask -from game.ground_forces.combat_stance import CombatStance - - -class AggressiveAttack(FrontLineStanceTask): - @property - def stance(self) -> CombatStance: - return CombatStance.AGGRESSIVE - - @property - def have_sufficient_front_line_advantage(self) -> bool: - return self.ground_force_balance >= 0.8 diff --git a/game/commander/tasks/primitive/antiship.py b/game/commander/tasks/primitive/antiship.py deleted file mode 100644 index cd3726ba8..000000000 --- a/game/commander/tasks/primitive/antiship.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.missionproposals import EscortType -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater.theatergroundobject import NavalGroundObject -from game.ato.flighttype import FlightType - - -@dataclass -class PlanAntiShip(PackagePlanningTask[NavalGroundObject]): - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.threatening_air_defenses: - return False - if not self.target_area_preconditions_met(state, ignore_iads=True): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.eliminate_ship(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.ANTISHIP, 2) - self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir) diff --git a/game/commander/tasks/primitive/antishipping.py b/game/commander/tasks/primitive/antishipping.py deleted file mode 100644 index 1c5e21444..000000000 --- a/game/commander/tasks/primitive/antishipping.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.transfers import CargoShip -from game.ato.flighttype import FlightType - - -@dataclass -class PlanAntiShipping(PackagePlanningTask[CargoShip]): - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.enemy_shipping: - return False - if not self.target_area_preconditions_met(state): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.enemy_shipping.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.ANTISHIP, 2) - self.propose_common_escorts() diff --git a/game/commander/tasks/primitive/bai.py b/game/commander/tasks/primitive/bai.py deleted file mode 100644 index a06c151e0..000000000 --- a/game/commander/tasks/primitive/bai.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater.theatergroundobject import VehicleGroupGroundObject -from game.ato.flighttype import FlightType - - -@dataclass -class PlanBai(PackagePlanningTask[VehicleGroupGroundObject]): - def preconditions_met(self, state: TheaterState) -> bool: - if not state.has_battle_position(self.target): - return False - if not self.target_area_preconditions_met(state): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.eliminate_battle_position(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.BAI, 2) - self.propose_common_escorts() diff --git a/game/commander/tasks/primitive/barcap.py b/game/commander/tasks/primitive/barcap.py deleted file mode 100644 index 4f2f96a58..000000000 --- a/game/commander/tasks/primitive/barcap.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater import ControlPoint -from game.ato.flighttype import FlightType - - -@dataclass -class PlanBarcap(PackagePlanningTask[ControlPoint]): - max_orders: int - - def preconditions_met(self, state: TheaterState) -> bool: - if not state.barcaps_needed[self.target]: - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.barcaps_needed[self.target] -= 1 - - def propose_flights(self) -> None: - self.propose_flight(FlightType.BARCAP, 2) - - @property - def purchase_multiplier(self) -> int: - return self.max_orders diff --git a/game/commander/tasks/primitive/breakthroughattack.py b/game/commander/tasks/primitive/breakthroughattack.py deleted file mode 100644 index a67a812e1..000000000 --- a/game/commander/tasks/primitive/breakthroughattack.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from game.commander.tasks.frontlinestancetask import FrontLineStanceTask -from game.commander.theaterstate import TheaterState -from game.ground_forces.combat_stance import CombatStance - - -class BreakthroughAttack(FrontLineStanceTask): - @property - def stance(self) -> CombatStance: - return CombatStance.BREAKTHROUGH - - @property - def have_sufficient_front_line_advantage(self) -> bool: - return self.ground_force_balance >= 2.0 - - def opposing_battle_positions_eliminated(self, state: TheaterState) -> bool: - battle_positions = state.enemy_battle_positions[self.enemy_cp] - return not bool(battle_positions.blocking_capture) - - def preconditions_met(self, state: TheaterState) -> bool: - if not super().preconditions_met(state): - return False - return self.opposing_battle_positions_eliminated(state) - - def apply_effects(self, state: TheaterState) -> None: - super().apply_effects(state) - state.active_front_lines.remove(self.front_line) diff --git a/game/commander/tasks/primitive/cas.py b/game/commander/tasks/primitive/cas.py deleted file mode 100644 index 2785da43d..000000000 --- a/game/commander/tasks/primitive/cas.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater import FrontLine -from game.ato.flighttype import FlightType - - -@dataclass -class PlanCas(PackagePlanningTask[FrontLine]): - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.vulnerable_front_lines: - return False - - # Do not bother planning CAS when there are no enemy ground units at the front. - # An exception is made for turn zero since that's not being truly planned, but - # just to determine what missions should be planned on turn 1 (when there *will* - # be ground units) and what aircraft should be ordered. - enemy_cp = self.target.control_point_friendly_to( - player=not state.context.coalition.player - ) - if enemy_cp.deployable_front_line_units == 0 and state.context.turn > 0: - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.vulnerable_front_lines.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.CAS, 2) - self.propose_flight(FlightType.TARCAP, 2) diff --git a/game/commander/tasks/primitive/convoyinterdiction.py b/game/commander/tasks/primitive/convoyinterdiction.py deleted file mode 100644 index 063d7a76a..000000000 --- a/game/commander/tasks/primitive/convoyinterdiction.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.data.doctrine import Doctrine -from game.transfers import Convoy -from game.ato.flighttype import FlightType - - -@dataclass -class PlanConvoyInterdiction(PackagePlanningTask[Convoy]): - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.enemy_convoys: - return False - if not self.target_area_preconditions_met(state): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.enemy_convoys.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.BAI, 2) - self.propose_common_escorts() diff --git a/game/commander/tasks/primitive/dead.py b/game/commander/tasks/primitive/dead.py deleted file mode 100644 index 4431577fa..000000000 --- a/game/commander/tasks/primitive/dead.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.missionproposals import EscortType -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater.theatergroundobject import IadsGroundObject -from game.ato.flighttype import FlightType - - -@dataclass -class PlanDead(PackagePlanningTask[IadsGroundObject]): - def preconditions_met(self, state: TheaterState) -> bool: - if ( - self.target not in state.threatening_air_defenses - and self.target not in state.detecting_air_defenses - ): - return False - if not self.target_area_preconditions_met(state, ignore_iads=True): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.eliminate_air_defense(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.DEAD, 2) - - # Only include SEAD against SAMs that still have emitters. No need to - # suppress an EWR, and SEAD isn't useful against a SAM that no longer has a - # working track radar. - # - # For SAMs without track radars and EWRs, we still want a SEAD escort if - # needed. - # - # Note that there is a quirk here: we should potentially be included a SEAD - # escort *and* SEAD when the target is a radar SAM but the flight path is - # also threatened by SAMs. We don't want to include a SEAD escort if the - # package is *only* threatened by the target though. Could be improved, but - # needs a decent refactor to the escort planning to do so. - if self.target.has_live_radar_sam: - self.propose_flight(FlightType.SEAD, 2) - else: - self.propose_flight(FlightType.SEAD_ESCORT, 2, EscortType.Sead) - self.propose_flight(FlightType.ESCORT, 2, EscortType.AirToAir) diff --git a/game/commander/tasks/primitive/defensivestance.py b/game/commander/tasks/primitive/defensivestance.py deleted file mode 100644 index a8e090842..000000000 --- a/game/commander/tasks/primitive/defensivestance.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from game.commander.tasks.frontlinestancetask import FrontLineStanceTask -from game.ground_forces.combat_stance import CombatStance - - -class DefensiveStance(FrontLineStanceTask): - @property - def stance(self) -> CombatStance: - return CombatStance.DEFENSIVE - - @property - def have_sufficient_front_line_advantage(self) -> bool: - return self.ground_force_balance >= 0.5 diff --git a/game/commander/tasks/primitive/eliminationattack.py b/game/commander/tasks/primitive/eliminationattack.py deleted file mode 100644 index 379f58c4f..000000000 --- a/game/commander/tasks/primitive/eliminationattack.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from game.commander.tasks.frontlinestancetask import FrontLineStanceTask -from game.ground_forces.combat_stance import CombatStance - - -class EliminationAttack(FrontLineStanceTask): - @property - def stance(self) -> CombatStance: - return CombatStance.ELIMINATION - - @property - def have_sufficient_front_line_advantage(self) -> bool: - return self.ground_force_balance >= 1.5 diff --git a/game/commander/tasks/primitive/oca.py b/game/commander/tasks/primitive/oca.py deleted file mode 100644 index 29b54e760..000000000 --- a/game/commander/tasks/primitive/oca.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater import ControlPoint -from game.ato.flighttype import FlightType - - -@dataclass -class PlanOcaStrike(PackagePlanningTask[ControlPoint]): - aircraft_cold_start: bool - - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.oca_targets: - return False - if not self.target_area_preconditions_met(state): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.oca_targets.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.OCA_RUNWAY, 2) - if self.aircraft_cold_start: - self.propose_flight(FlightType.OCA_AIRCRAFT, 2) - self.propose_common_escorts() diff --git a/game/commander/tasks/primitive/refueling.py b/game/commander/tasks/primitive/refueling.py deleted file mode 100644 index f43e4941d..000000000 --- a/game/commander/tasks/primitive/refueling.py +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater import MissionTarget -from game.ato.flighttype import FlightType - - -@dataclass -class PlanRefueling(PackagePlanningTask[MissionTarget]): - def preconditions_met(self, state: TheaterState) -> bool: - if not super().preconditions_met(state): - return False - return self.target in state.refueling_targets - - def apply_effects(self, state: TheaterState) -> None: - state.refueling_targets.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.REFUELING, 1) diff --git a/game/commander/tasks/primitive/retreatstance.py b/game/commander/tasks/primitive/retreatstance.py deleted file mode 100644 index 0e1793669..000000000 --- a/game/commander/tasks/primitive/retreatstance.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from game.commander.tasks.frontlinestancetask import FrontLineStanceTask -from game.ground_forces.combat_stance import CombatStance - - -class RetreatStance(FrontLineStanceTask): - @property - def stance(self) -> CombatStance: - return CombatStance.RETREAT - - @property - def have_sufficient_front_line_advantage(self) -> bool: - return True diff --git a/game/commander/tasks/primitive/strike.py b/game/commander/tasks/primitive/strike.py deleted file mode 100644 index 8bb4a9c52..000000000 --- a/game/commander/tasks/primitive/strike.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any - -from game.commander.tasks.packageplanningtask import PackagePlanningTask -from game.commander.theaterstate import TheaterState -from game.theater.theatergroundobject import TheaterGroundObject -from game.ato.flighttype import FlightType - - -@dataclass -class PlanStrike(PackagePlanningTask[TheaterGroundObject]): - def preconditions_met(self, state: TheaterState) -> bool: - if self.target not in state.strike_targets: - return False - if not self.target_area_preconditions_met(state): - return False - return super().preconditions_met(state) - - def apply_effects(self, state: TheaterState) -> None: - state.strike_targets.remove(self.target) - - def propose_flights(self) -> None: - self.propose_flight(FlightType.STRIKE, 2) - self.propose_common_escorts() diff --git a/game/commander/tasks/theatercommandertask.py b/game/commander/tasks/theatercommandertask.py deleted file mode 100644 index 5daa6b6cd..000000000 --- a/game/commander/tasks/theatercommandertask.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -from abc import abstractmethod -from typing import TYPE_CHECKING - -from game.commander.theaterstate import TheaterState -from game.htn import PrimitiveTask - -if TYPE_CHECKING: - from game.coalition import Coalition - - -class TheaterCommanderTask(PrimitiveTask[TheaterState]): - @abstractmethod - def execute(self, coalition: Coalition) -> None: - ... diff --git a/game/commander/theatercommander.py b/game/commander/theatercommander.py deleted file mode 100644 index 0bc638289..000000000 --- a/game/commander/theatercommander.py +++ /dev/null @@ -1,90 +0,0 @@ -"""The Theater Commander is the highest level campaign AI. - -Target selection is performed with a hierarchical-task-network (HTN, linked below). -These work by giving the planner an initial "task" which decomposes into other tasks -until a concrete set of actions is formed. For example, the "capture base" task may -decompose in the following manner: - -* Defend - * Reinforce front line - * Set front line stance to defend - * Destroy enemy front line units - * Set front line stance to elimination - * Plan CAS at front line -* Prepare - * Destroy enemy IADS - * Plan DEAD against SAM Armadillo - * ... - * Destroy enemy front line units - * Set front line stance to elimination - * Plan CAS at front line -* Inhibit - * Destroy enemy unit production infrastructure - * Destroy factory at Palmyra - * ... - * Destroy enemy front line units - * Set front line stance to elimination - * Plan CAS at front line -* Attack - * Set front line stance to breakthrough - * Destroy enemy front line units - * Set front line stance to elimination - * Plan CAS at front line - -This is not a reflection of the actual task composition but illustrates the capability -of the system. Each task has preconditions which are checked before the task is -decomposed. If preconditions are not met the task is ignored and the next is considered. -For example the task to destroy the factory at Palmyra might be excluded until the air -defenses protecting it are eliminated; or defensive air operations might be excluded if -the enemy does not have sufficient air forces, or if the protected target has sufficient -SAM coverage. - -Each action updates the world state, which causes each action to account for the result -of the tasks executed before it. Above, the preconditions for attacking the factory at -Palmyra may not have been met due to the IADS coverage, leading the planning to decide -on an attack against the IADS in the area instead. When planning the next task in the -same turn, the world state will have been updated to account for the (hopefully) -destroyed SAM sites, allowing the planner to choose the mission to attack the factory. - -Preconditions can be aware of previous actions as well. A precondition for "Plan CAS at -front line" can be "No CAS missions planned at front line" to avoid over-planning CAS -even though it is a primitive task used by many other tasks. - -https://en.wikipedia.org/wiki/Hierarchical_task_network -""" -from __future__ import annotations - -from datetime import datetime -from typing import TYPE_CHECKING - -from game.ato.starttype import StartType -from game.commander.tasks.compound.nextaction import PlanNextAction -from game.commander.tasks.theatercommandertask import TheaterCommanderTask -from game.commander.theaterstate import TheaterState -from game.htn import Planner -from game.profiling import MultiEventTracer - -if TYPE_CHECKING: - from game import Game - - -class TheaterCommander(Planner[TheaterState, TheaterCommanderTask]): - def __init__(self, game: Game, player: bool) -> None: - super().__init__( - PlanNextAction( - aircraft_cold_start=game.settings.default_start_type is StartType.COLD - ) - ) - self.game = game - self.player = player - - def plan_missions(self, now: datetime, tracer: MultiEventTracer) -> None: - state = TheaterState.from_game(self.game, self.player, now, tracer) - while True: - result = self.plan(state) - if result is None: - # Planned all viable tasks this turn. - return - for task in result.tasks: - task.execute(self.game.coalition_for(self.player)) - state = result.end_state diff --git a/game/commander/theaterstate.py b/game/commander/theaterstate.py deleted file mode 100644 index bc8d7166c..000000000 --- a/game/commander/theaterstate.py +++ /dev/null @@ -1,193 +0,0 @@ -from __future__ import annotations - -import dataclasses -import itertools -import math -from collections.abc import Iterator -from dataclasses import dataclass -from datetime import datetime -from typing import Optional, TYPE_CHECKING, Union - -from game.commander.battlepositions import BattlePositions -from game.commander.objectivefinder import ObjectiveFinder -from game.db import GameDb -from game.ground_forces.combat_stance import CombatStance -from game.htn import WorldState -from game.profiling import MultiEventTracer -from game.settings import Settings -from game.theater import ConflictTheater, ControlPoint, FrontLine, MissionTarget -from game.theater.theatergroundobject import ( - BuildingGroundObject, - IadsGroundObject, - NavalGroundObject, - TheaterGroundObject, - VehicleGroupGroundObject, -) -from game.threatzones import ThreatZones - -if TYPE_CHECKING: - from game import Game - from game.coalition import Coalition - from game.transfers import Convoy, CargoShip - - -@dataclass(frozen=True) -class PersistentContext: - game_db: GameDb - coalition: Coalition - theater: ConflictTheater - turn: int - now: datetime - settings: Settings - tracer: MultiEventTracer - - -@dataclass -class TheaterState(WorldState["TheaterState"]): - context: PersistentContext - barcaps_needed: dict[ControlPoint, int] - active_front_lines: list[FrontLine] - front_line_stances: dict[FrontLine, Optional[CombatStance]] - vulnerable_front_lines: list[FrontLine] - aewc_targets: list[MissionTarget] - refueling_targets: list[MissionTarget] - enemy_air_defenses: list[IadsGroundObject] - threatening_air_defenses: list[Union[IadsGroundObject, NavalGroundObject]] - detecting_air_defenses: list[Union[IadsGroundObject, NavalGroundObject]] - enemy_convoys: list[Convoy] - enemy_shipping: list[CargoShip] - enemy_ships: list[NavalGroundObject] - enemy_battle_positions: dict[ControlPoint, BattlePositions] - oca_targets: list[ControlPoint] - strike_targets: list[TheaterGroundObject] - enemy_barcaps: list[ControlPoint] - threat_zones: ThreatZones - - def _rebuild_threat_zones(self) -> None: - """Recreates the theater's threat zones based on the current planned state.""" - self.threat_zones = ThreatZones.for_threats( - self.context.theater, - self.context.coalition.opponent.doctrine, - barcap_locations=self.enemy_barcaps, - air_defenses=itertools.chain(self.enemy_air_defenses, self.enemy_ships), - ) - - def eliminate_air_defense(self, target: IadsGroundObject) -> None: - if target in self.threatening_air_defenses: - self.threatening_air_defenses.remove(target) - if target in self.detecting_air_defenses: - self.detecting_air_defenses.remove(target) - self.enemy_air_defenses.remove(target) - self._rebuild_threat_zones() - - def eliminate_ship(self, target: NavalGroundObject) -> None: - if target in self.threatening_air_defenses: - self.threatening_air_defenses.remove(target) - if target in self.detecting_air_defenses: - self.detecting_air_defenses.remove(target) - self.enemy_ships.remove(target) - self._rebuild_threat_zones() - - def has_battle_position(self, target: VehicleGroupGroundObject) -> bool: - return target in self.enemy_battle_positions[target.control_point] - - def eliminate_battle_position(self, target: VehicleGroupGroundObject) -> None: - self.enemy_battle_positions[target.control_point].eliminate(target) - - def ammo_dumps_at( - self, control_point: ControlPoint - ) -> Iterator[BuildingGroundObject]: - for target in self.strike_targets: - if target.control_point != control_point: - continue - if target.is_ammo_depot: - assert isinstance(target, BuildingGroundObject) - yield target - - def clone(self) -> TheaterState: - # Do not use copy.deepcopy. Copying every TGO, control point, etc is absurdly - # expensive. - return TheaterState( - context=self.context, - barcaps_needed=dict(self.barcaps_needed), - active_front_lines=list(self.active_front_lines), - front_line_stances=dict(self.front_line_stances), - vulnerable_front_lines=list(self.vulnerable_front_lines), - aewc_targets=list(self.aewc_targets), - refueling_targets=list(self.refueling_targets), - enemy_air_defenses=list(self.enemy_air_defenses), - enemy_convoys=list(self.enemy_convoys), - enemy_shipping=list(self.enemy_shipping), - enemy_ships=list(self.enemy_ships), - enemy_battle_positions={ - cp: dataclasses.replace(g) - for cp, g in self.enemy_battle_positions.items() - }, - oca_targets=list(self.oca_targets), - strike_targets=list(self.strike_targets), - enemy_barcaps=list(self.enemy_barcaps), - threat_zones=self.threat_zones, - # Persistent properties are not copied. These are a way for failed subtasks - # to communicate requirements to other tasks. For example, the task to - # attack enemy battle_positions might fail because the target area has IADS - # protection. In that case, the preconditions of PlanBai would fail, but - # would add the IADS that prevented it from being planned to the list of - # IADS threats so that DegradeIads will consider it a threat later. - threatening_air_defenses=self.threatening_air_defenses, - detecting_air_defenses=self.detecting_air_defenses, - ) - - @classmethod - def from_game( - cls, game: Game, player: bool, now: datetime, tracer: MultiEventTracer - ) -> TheaterState: - coalition = game.coalition_for(player) - finder = ObjectiveFinder(game, player) - ordered_capturable_points = finder.prioritized_unisolated_points() - - context = PersistentContext( - game.db, - coalition, - game.theater, - game.turn, - now, - game.settings, - tracer, - ) - - # Plan enough rounds of CAP that the target has coverage over the expected - # mission duration. - mission_duration = game.settings.desired_player_mission_duration.total_seconds() - barcap_duration = coalition.doctrine.cap.duration.total_seconds() - barcap_rounds = math.ceil(mission_duration / barcap_duration) - - refueling_targets: list[MissionTarget] = [] - theater_refuling_point = finder.preferred_theater_refueling_control_point() - if theater_refuling_point is not None: - refueling_targets.append(theater_refuling_point) - - return TheaterState( - context=context, - barcaps_needed={ - cp: barcap_rounds for cp in finder.vulnerable_control_points() - }, - active_front_lines=list(finder.front_lines()), - front_line_stances={f: None for f in finder.front_lines()}, - vulnerable_front_lines=list(finder.front_lines()), - aewc_targets=[finder.farthest_friendly_control_point()], - refueling_targets=refueling_targets, - enemy_air_defenses=list(finder.enemy_air_defenses()), - threatening_air_defenses=[], - detecting_air_defenses=[], - enemy_convoys=list(finder.convoys()), - enemy_shipping=list(finder.cargo_ships()), - enemy_ships=list(finder.enemy_ships()), - enemy_battle_positions={ - cp: BattlePositions.for_control_point(cp) - for cp in ordered_capturable_points - }, - oca_targets=list(finder.oca_targets(min_aircraft=20)), - strike_targets=list(finder.strike_targets()), - enemy_barcaps=list(game.theater.control_points_for(not player)), - threat_zones=game.threat_zone_for(not player), - ) diff --git a/game/config.py b/game/config.py deleted file mode 100644 index 2a55fc379..000000000 --- a/game/config.py +++ /dev/null @@ -1,19 +0,0 @@ -# This should probably be much higher, but the AI doesn't rollover their budget -# and isn't smart enough to save to repair a critical runway anyway, so it has -# to be cheap enough to repair with a single turn's income. -RUNWAY_REPAIR_COST = 100 - -REWARDS = { - "warehouse": 2, - "ware": 2, - "fuel": 2, - "ammo": 2, - "farp": 1, - # TODO: Should generate no cash once they generate units. - # https://github.com/dcs-liberation/dcs_liberation/issues/1036 - "factory": 2.5, - "oil": 10, - "derrick": 8, - "village": 0.25, - "allycamp": 0.5, -} diff --git a/game/data/__init__.py b/game/data/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/data/alic.py b/game/data/alic.py deleted file mode 100644 index ac884085f..000000000 --- a/game/data/alic.py +++ /dev/null @@ -1,43 +0,0 @@ -from dcs.vehicles import AirDefence - -from game.theater.theatergroup import TheaterUnit - - -class AlicCodes: - CODES = { - AirDefence.X_1L13_EWR.id: 101, - AirDefence.X_55G6_EWR.id: 102, - AirDefence.S_300PS_40B6MD_sr.id: 103, - AirDefence.S_300PS_64H6E_sr.id: 104, - AirDefence.SA_11_Buk_SR_9S18M1.id: 107, - AirDefence.Kub_1S91_str.id: 108, - AirDefence.Dog_Ear_radar.id: 109, - AirDefence.S_300PS_40B6M_tr.id: 110, - AirDefence.SA_11_Buk_LN_9A310M1.id: 115, - AirDefence.Osa_9A33_ln.id: 117, - AirDefence.Strela_10M3.id: 118, - AirDefence.Tor_9A331.id: 119, - AirDefence.X_2S6_Tunguska.id: 120, - AirDefence.ZSU_23_4_Shilka.id: 121, - AirDefence.P_19_s_125_sr.id: 122, - AirDefence.Snr_s_125_tr.id: 123, - AirDefence.Rapier_fsa_blindfire_radar.id: 124, - AirDefence.Rapier_fsa_launcher.id: 125, - AirDefence.SNR_75V.id: 126, - AirDefence.HQ_7_LN_SP.id: 127, - AirDefence.HQ_7_STR_SP.id: 128, - AirDefence.RLS_19J6.id: 130, - AirDefence.Roland_ADS.id: 201, - AirDefence.Patriot_str.id: 202, - AirDefence.Hawk_sr.id: 203, - AirDefence.Hawk_tr.id: 204, - AirDefence.Roland_Radar.id: 205, - AirDefence.Hawk_cwar.id: 206, - AirDefence.Gepard.id: 207, - AirDefence.Vulcan.id: 208, - AirDefence.NASAMS_Radar_MPQ64F1.id: 209, - } - - @classmethod - def code_for(cls, unit: TheaterUnit) -> int: - return cls.CODES[unit.type.id] diff --git a/game/data/building_data.py b/game/data/building_data.py deleted file mode 100644 index d50c6c0f7..000000000 --- a/game/data/building_data.py +++ /dev/null @@ -1,74 +0,0 @@ -import inspect - -import dcs - -REQUIRED_BUILDINGS = [ - "ammo", - "factory", - "fob", - "oil", -] - -IADS_BUILDINGS = [ - "comms", - "power", - "commandcenter", -] - -DEFAULT_AVAILABLE_BUILDINGS = [ - "fuel", - "ware", - "farp", - "derrick", -] - -WW2_FREE = ["fuel", "ware"] -WW2_GERMANY_BUILDINGS = [ - "fuel", - "ww2bunker", - "ww2bunker", - "ww2bunker", - "allycamp", - "allycamp", -] -WW2_ALLIES_BUILDINGS = [ - "fuel", - "allycamp", - "allycamp", - "allycamp", - "allycamp", - "allycamp", -] - -FORTIFICATION_BUILDINGS = [ - "Siegfried Line", - "Concertina wire", - "Concertina Wire", - "Czech hedgehogs 1", - "Czech hedgehogs 2", - "Dragonteeth 1", - "Dragonteeth 2", - "Dragonteeth 3", - "Dragonteeth 4", - "Dragonteeth 5", - "Haystack 1", - "Haystack 2", - "Haystack 3", - "Haystack 4", - "Hemmkurvenvenhindernis", - "Log posts 1", - "Log posts 2", - "Log posts 3", - "Log ramps 1", - "Log ramps 2", - "Log ramps 3", - "Belgian Gate", - "Container white", -] - -FORTIFICATION_UNITS = [ - c for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c) -] -FORTIFICATION_UNITS_ID = [ - c.id for c in vars(dcs.vehicles.Fortification).values() if inspect.isclass(c) -] diff --git a/game/data/doctrine.py b/game/data/doctrine.py deleted file mode 100644 index 91f5b81ad..000000000 --- a/game/data/doctrine.py +++ /dev/null @@ -1,224 +0,0 @@ -from __future__ import annotations - -from pathlib import Path -import yaml -from typing import Any, ClassVar - -from dataclasses import dataclass -from datetime import timedelta - -from game.data.units import UnitClass -from game.utils import Distance, feet, nautical_miles - - -@dataclass -class GroundUnitProcurementRatios: - ratios: dict[UnitClass, float] - - def for_unit_class(self, unit_class: UnitClass) -> float: - try: - return self.ratios[unit_class] / sum(self.ratios.values()) - except KeyError: - return 0.0 - - @staticmethod - def from_dict(data: dict[str, float]) -> GroundUnitProcurementRatios: - unit_class_enum_from_name = {unit.value: unit for unit in UnitClass} - r = {} - for unit_class in data: - if unit_class not in unit_class_enum_from_name: - raise ValueError(f"Could not find unit type {unit_class}") - r[unit_class_enum_from_name[unit_class]] = float(data[unit_class]) - return GroundUnitProcurementRatios(r) - - -@dataclass -class Helicopter: - #: The altitude used for combat section of a flight, overrides the base combat_altitude parameter for helos - combat_altitude: Distance - - #: The altitude used for forming up a pacakge. Overrides the base rendezvous_altitude parameter for helos - rendezvous_altitude: Distance - - #: Altitude of the nav points (cruise section) of air assault missions. - air_assault_nav_altitude: Distance - - @staticmethod - def from_dict(data: dict[str, Any]) -> Helicopter: - return Helicopter( - combat_altitude=feet(data["combat_altitude_ft_agl"]), - rendezvous_altitude=feet(data["rendezvous_altitude_ft_agl"]), - air_assault_nav_altitude=feet(data["air_assault_nav_altitude_ft_agl"]), - ) - - -@dataclass -class Cas: - #: The duration that CAP flights will remain on-station. - duration: timedelta - - @staticmethod - def from_dict(data: dict[str, Any]) -> Cas: - return Cas(duration=timedelta(minutes=data["duration_minutes"])) - - -@dataclass -class Sweep: - #: Length of the sweep / patrol leg - distance: Distance - - @staticmethod - def from_dict(data: dict[str, Any]) -> Sweep: - return Sweep( - distance=nautical_miles(data["distance_nm"]), - ) - - -@dataclass -class Cap: - #: The duration that CAP flights will remain on-station. - duration: timedelta - - #: The minimum length of the CAP race track. - min_track_length: Distance - - #: The maximum length of the CAP race track. - max_track_length: Distance - - #: The minimum distance between the defended position and the *end* of the - #: CAP race track. - min_distance_from_cp: Distance - - #: The maximum distance between the defended position and the *end* of the - #: CAP race track. - max_distance_from_cp: Distance - - #: The engagement range of CAP flights. Any enemy aircraft within this range - #: of the CAP's current position will be engaged by the CAP. - engagement_range: Distance - - #: Defines the range of altitudes CAP racetracks are planned at. - min_patrol_altitude: Distance - max_patrol_altitude: Distance - - @staticmethod - def from_dict(data: dict[str, Any]) -> Cap: - return Cap( - duration=timedelta(minutes=data["duration_minutes"]), - min_track_length=nautical_miles(data["min_track_length_nm"]), - max_track_length=nautical_miles(data["max_track_length_nm"]), - min_distance_from_cp=nautical_miles(data["min_distance_from_cp_nm"]), - max_distance_from_cp=nautical_miles(data["max_distance_from_cp_nm"]), - engagement_range=nautical_miles(data["engagement_range_nm"]), - min_patrol_altitude=feet(data["min_patrol_altitude_ft_msl"]), - max_patrol_altitude=feet(data["max_patrol_altitude_ft_msl"]), - ) - - -@dataclass(frozen=True) -class Doctrine: - #: Name of the doctrine, used to assign a doctrine in a faction. - name: str - - #: The minimum distance between the departure airfield and the hold point. - hold_distance: Distance - - #: The minimum distance between the hold point and the join point. - push_distance: Distance - - #: The distance between the join point and the ingress point. Only used for the - #: fallback flight plan layout (when the departure airfield is near a threat zone). - join_distance: Distance - - #: The maximum distance between the ingress point (beginning of the attack) and - #: target. - max_ingress_distance: Distance - - #: The minimum distance between the ingress point (beginning of the attack) and - #: target. - min_ingress_distance: Distance - - #: The altitude used for combat section of a flight. - combat_altitude: Distance - - #: The altitude used for forming up a pacakge. - rendezvous_altitude: Distance - - #: Defines prioritization of ground unit purchases. - ground_unit_procurement_ratios: GroundUnitProcurementRatios - - #: Helicopter specific doctrines. - helicopter: Helicopter - - #: Doctrine for CAS missions. - cas: Cas - - #: Doctrine for CAP missions. - cap: Cap - - #: Doctrine for Fighter Sweep missions. - sweep: Sweep - - _by_name: ClassVar[dict[str, Doctrine]] = {} - _loaded: ClassVar[bool] = False - - def resolve_combat_altitude(self, is_helo: bool = False) -> Distance: - if is_helo: - return self.helicopter.combat_altitude - return self.combat_altitude - - def resolve_rendezvous_altitude(self, is_helo: bool = False) -> Distance: - if is_helo: - return self.helicopter.rendezvous_altitude - return self.rendezvous_altitude - - @classmethod - def register(cls, doctrine: Doctrine) -> None: - if doctrine.name in cls._by_name: - duplicate = cls._by_name[doctrine.name] - raise ValueError(f"Doctrine {doctrine.name} is already loaded") - cls._by_name[doctrine.name] = doctrine - - @classmethod - def named(cls, name: str) -> Doctrine: - if not cls._loaded: - cls.load_all() - return cls._by_name[name] - - @classmethod - def all_doctrines(cls) -> list[Doctrine]: - if not cls._loaded: - cls.load_all() - return list(cls._by_name.values()) - - @classmethod - def load_all(cls) -> None: - if cls._loaded: - return - for doctrine_file_path in Path("resources/doctrines").glob("**/*.yaml"): - with doctrine_file_path.open(encoding="utf8") as doctrine_file: - data = yaml.safe_load(doctrine_file) - cls.register( - Doctrine( - name=data["name"], - rendezvous_altitude=feet(data["rendezvous_altitude_ft_msl"]), - hold_distance=nautical_miles(data["hold_distance_nm"]), - push_distance=nautical_miles(data["push_distance_nm"]), - join_distance=nautical_miles(data["join_distance_nm"]), - max_ingress_distance=nautical_miles( - data["max_ingress_distance_nm"] - ), - min_ingress_distance=nautical_miles( - data["min_ingress_distance_nm"] - ), - combat_altitude=feet(data["combat_altitude_ft_msl"]), - ground_unit_procurement_ratios=GroundUnitProcurementRatios.from_dict( - data["ground_unit_procurement_ratios"] - ), - helicopter=Helicopter.from_dict(data["helicopter"]), - cas=Cas.from_dict(data["cas"]), - cap=Cap.from_dict(data["cap"]), - sweep=Sweep.from_dict(data["sweep"]), - ) - ) - cls._loaded = True diff --git a/game/data/groups.py b/game/data/groups.py deleted file mode 100644 index 9f792f82e..000000000 --- a/game/data/groups.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import annotations - -from enum import Enum - - -class GroupRole(Enum): - """Role of a ForceGroup within the ArmedForces""" - - AIR_DEFENSE = "AntiAir" - BUILDING = "Building" - DEFENSES = "Defenses" - GROUND_FORCE = "GroundForce" - NAVAL = "Naval" - - @property - def tasks(self) -> list[GroupTask]: - return [task for task in GroupTask if task.role == self] - - -class GroupTask(Enum): - """Specific Tasking of a ForceGroup""" - - def __init__(self, description: str, role: GroupRole): - self.description = description - self.role = role - - @classmethod - def by_description(cls, description: str) -> GroupTask: - for task in GroupTask: - if task.description == description: - return task - raise RuntimeError(f"GroupTask with description {description} does not exist") - - # ANTI AIR - AAA = ("AAA", GroupRole.AIR_DEFENSE) - EARLY_WARNING_RADAR = ("EarlyWarningRadar", GroupRole.AIR_DEFENSE) - LORAD = ("LORAD", GroupRole.AIR_DEFENSE) - MERAD = ("MERAD", GroupRole.AIR_DEFENSE) - SHORAD = ("SHORAD", GroupRole.AIR_DEFENSE) - POINT_DEFENSE = ("PointDefense", GroupRole.AIR_DEFENSE) - - # NAVAL - AIRCRAFT_CARRIER = ("AircraftCarrier", GroupRole.NAVAL) - HELICOPTER_CARRIER = ("HelicopterCarrier", GroupRole.NAVAL) - NAVY = ("Navy", GroupRole.NAVAL) - - # GROUND FORCES - BASE_DEFENSE = ("BaseDefense", GroupRole.GROUND_FORCE) - FRONT_LINE = ("FrontLine", GroupRole.GROUND_FORCE) - - # DEFENSES - COASTAL = ("Coastal", GroupRole.DEFENSES) - MISSILE = ("Missile", GroupRole.DEFENSES) - - # BUILDINGS - ALLY_CAMP = ("AllyCamp", GroupRole.BUILDING) - AMMO = ("Ammo", GroupRole.BUILDING) - DERRICK = ("Derrick", GroupRole.BUILDING) - FACTORY = ("Factory", GroupRole.BUILDING) - FARP = ("Farp", GroupRole.BUILDING) - FOB = ("FOB", GroupRole.BUILDING) - FUEL = ("Fuel", GroupRole.BUILDING) - OFFSHORE_STRIKE_TARGET = ("OffShoreStrikeTarget", GroupRole.BUILDING) - OIL = ("Oil", GroupRole.BUILDING) - - STRIKE_TARGET = ("StrikeTarget", GroupRole.BUILDING) - VILLAGE = ("Village", GroupRole.BUILDING) - WARE = ("Ware", GroupRole.BUILDING) - WW2_BUNKER = ("WW2Bunker", GroupRole.BUILDING) - - # IADS - COMMS = ("Comms", GroupRole.BUILDING) - COMMAND_CENTER = ("CommandCenter", GroupRole.BUILDING) - POWER = ("Power", GroupRole.BUILDING) diff --git a/game/data/radar_db.py b/game/data/radar_db.py deleted file mode 100644 index cc92bcb11..000000000 --- a/game/data/radar_db.py +++ /dev/null @@ -1,137 +0,0 @@ -from dcs.ships import ( - ALBATROS, - CVN_71, - CVN_72, - CVN_73, - CV_1143_5, - Forrestal, - KUZNECOW, - LHA_Tarawa, - MOLNIYA, - MOSCOW, - NEUSTRASH, - PERRY, - PIOTR, - REZKY, - Stennis, - TICONDEROG, - Type_052B, - Type_052C, - Type_054A, - USS_Arleigh_Burke_IIa, - VINSON, -) -from dcs.vehicles import AirDefence - -from pydcs_extensions import highdigitsams as hds - -TELARS = { - AirDefence.X_2S6_Tunguska, - AirDefence.SA_11_Buk_LN_9A310M1, - AirDefence.Osa_9A33_ln, - AirDefence.Tor_9A331, - AirDefence.Roland_ADS, - hds.SAM_SA_17_Buk_M1_2_LN_9A310M1_2, -} - -TRACK_RADARS = { - AirDefence.Kub_1S91_str, - AirDefence.Snr_s_125_tr, - AirDefence.S_300PS_40B6M_tr, - AirDefence.Hawk_tr, - AirDefence.Patriot_str, - AirDefence.SNR_75V, - AirDefence.RPC_5N62V, - AirDefence.Rapier_fsa_blindfire_radar, - AirDefence.HQ_7_STR_SP, - AirDefence.NASAMS_Radar_MPQ64F1, - hds.SAM_SA_10B_S_300PS_30N6_TR, - hds.SAM_SA_12_S_300V_9S32_TR, - hds.SAM_SA_20_S_300PMU1_TR_30N6E, - hds.SAM_SA_20B_S_300PMU2_TR_92H6E_truck, - hds.SAM_SA_23_S_300VM_9S32ME_TR, -} - -LAUNCHER_TRACKER_PAIRS = { - AirDefence.Kub_2P25_ln: AirDefence.Kub_1S91_str, - AirDefence.X_5p73_s_125_ln: AirDefence.Snr_s_125_tr, - AirDefence.S_300PS_5P85C_ln: AirDefence.S_300PS_40B6M_tr, - AirDefence.S_300PS_5P85D_ln: AirDefence.S_300PS_40B6M_tr, - AirDefence.Hawk_ln: AirDefence.Hawk_tr, - AirDefence.Patriot_ln: AirDefence.Patriot_str, - AirDefence.S_75M_Volhov: AirDefence.SNR_75V, - AirDefence.Rapier_fsa_launcher: AirDefence.Rapier_fsa_blindfire_radar, - AirDefence.HQ_7_LN_SP: AirDefence.HQ_7_STR_SP, - AirDefence.S_200_Launcher: AirDefence.RPC_5N62V, - AirDefence.NASAMS_LN_B: AirDefence.NASAMS_Radar_MPQ64F1, - AirDefence.NASAMS_LN_C: AirDefence.NASAMS_Radar_MPQ64F1, - hds.SAM_SA_2__V759__LN_SM_90: AirDefence.SNR_75V, - hds.SAM_HQ_2_LN_SM_90: AirDefence.SNR_75V, - hds.SAM_SA_3__V_601P__LN_5P73: AirDefence.Snr_s_125_tr, - hds.SAM_SA_10B_S_300PS_5P85SE_LN: hds.SAM_SA_10B_S_300PS_30N6_TR, - hds.SAM_SA_10B_S_300PS_5P85SU_LN: hds.SAM_SA_10B_S_300PS_30N6_TR, - hds.SAM_SA_12_S_300V_9A82_LN: hds.SAM_SA_12_S_300V_9S32_TR, - hds.SAM_SA_12_S_300V_9A83_LN: hds.SAM_SA_12_S_300V_9S32_TR, - hds.SAM_SA_20_S_300PMU1_LN_5P85CE: hds.SAM_SA_20_S_300PMU1_TR_30N6E, - hds.SAM_SA_20_S_300PMU1_LN_5P85DE: hds.SAM_SA_20_S_300PMU1_TR_30N6E, - hds.SAM_SA_20B_S_300PMU2_LN_5P85SE2: hds.SAM_SA_20B_S_300PMU2_TR_92H6E_truck, - hds.SAM_SA_23_S_300VM_9A82ME_LN: hds.SAM_SA_23_S_300VM_9S32ME_TR, - hds.SAM_SA_23_S_300VM_9A83ME_LN: hds.SAM_SA_23_S_300VM_9S32ME_TR, -} - -UNITS_WITH_RADAR = { - # Radars - AirDefence.X_2S6_Tunguska, - AirDefence.SA_11_Buk_LN_9A310M1, - AirDefence.Osa_9A33_ln, - AirDefence.Tor_9A331, - AirDefence.Gepard, - AirDefence.Vulcan, - AirDefence.Roland_ADS, - AirDefence.ZSU_23_4_Shilka, - AirDefence.X_1L13_EWR, - AirDefence.Kub_1S91_str, - AirDefence.S_300PS_40B6M_tr, - AirDefence.S_300PS_40B6MD_sr, - AirDefence.X_55G6_EWR, - AirDefence.S_300PS_64H6E_sr, - AirDefence.SA_11_Buk_SR_9S18M1, - AirDefence.Dog_Ear_radar, - AirDefence.Hawk_tr, - AirDefence.Hawk_sr, - AirDefence.Patriot_str, - AirDefence.Hawk_cwar, - AirDefence.P_19_s_125_sr, - AirDefence.Roland_Radar, - AirDefence.Snr_s_125_tr, - AirDefence.SNR_75V, - AirDefence.RLS_19J6, - AirDefence.RPC_5N62V, - AirDefence.Rapier_fsa_blindfire_radar, - AirDefence.HQ_7_LN_SP, - AirDefence.HQ_7_STR_SP, - AirDefence.FuMG_401, - AirDefence.FuSe_65, - # Ships - ALBATROS, - CVN_71, - CVN_72, - CVN_73, - CV_1143_5, - Forrestal, - KUZNECOW, - LHA_Tarawa, - MOLNIYA, - MOSCOW, - NEUSTRASH, - PERRY, - PIOTR, - REZKY, - Stennis, - TICONDEROG, - Type_052B, - Type_052C, - Type_054A, - USS_Arleigh_Burke_IIa, - VINSON, -} diff --git a/game/data/units.py b/game/data/units.py deleted file mode 100644 index 20b5b21b5..000000000 --- a/game/data/units.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -from enum import unique, Enum - - -@unique -class UnitClass(Enum): - UNKNOWN = "Unknown" - AAA = "AAA" - AIRCRAFT_CARRIER = "AircraftCarrier" - APC = "APC" - ARTILLERY = "Artillery" - ATGM = "ATGM" - BOAT = "Boat" - COMMAND_POST = "CommandPost" - CRUISER = "Cruiser" - DESTROYER = "Destroyer" - EARLY_WARNING_RADAR = "EarlyWarningRadar" - FORTIFICATION = "Fortification" - FRIGATE = "Frigate" - HELICOPTER = "Helicopter" - HELICOPTER_CARRIER = "HelicopterCarrier" - IFV = "IFV" - INFANTRY = "Infantry" - LANDING_SHIP = "LandingShip" - LAUNCHER = "Launcher" - LOGISTICS = "Logistics" - MANPAD = "Manpad" - MISSILE = "Missile" - ANTISHIP_MISSILE = "AntiShipMissile" - OPTICAL_TRACKER = "OpticalTracker" - PLANE = "Plane" - POWER = "Power" - RECON = "Recon" - SEARCH_LIGHT = "SearchLight" - SEARCH_RADAR = "SearchRadar" - SEARCH_TRACK_RADAR = "SearchTrackRadar" - SHORAD = "SHORAD" - SPECIALIZED_RADAR = "SpecializedRadar" - SUBMARINE = "Submarine" - TANK = "Tank" - TELAR = "TELAR" - TRACK_RADAR = "TrackRadar" - - -# All UnitClasses which can have AntiAir capabilities -ANTI_AIR_UNIT_CLASSES = [ - UnitClass.AAA, - UnitClass.AIRCRAFT_CARRIER, - UnitClass.CRUISER, - UnitClass.DESTROYER, - UnitClass.EARLY_WARNING_RADAR, - UnitClass.FRIGATE, - UnitClass.HELICOPTER_CARRIER, - UnitClass.LAUNCHER, - UnitClass.MANPAD, - UnitClass.SEARCH_RADAR, - UnitClass.SEARCH_TRACK_RADAR, - UnitClass.SPECIALIZED_RADAR, - UnitClass.SHORAD, - UnitClass.SUBMARINE, - UnitClass.TELAR, - UnitClass.TRACK_RADAR, -] diff --git a/game/data/weapons.py b/game/data/weapons.py deleted file mode 100644 index 13df6d876..000000000 --- a/game/data/weapons.py +++ /dev/null @@ -1,278 +0,0 @@ -from __future__ import annotations - -import datetime -import inspect -import logging -from dataclasses import dataclass, field -from enum import unique, Enum -from functools import cached_property -from pathlib import Path -from typing import Iterator, Optional, Any, ClassVar - -import yaml -from dcs.flyingunit import FlyingUnit -from dcs.weapons_data import weapon_ids - -from game.dcs.aircrafttype import AircraftType - -PydcsWeapon = Any -PydcsWeaponAssignment = tuple[int, PydcsWeapon] - - -@dataclass(frozen=True) -class Weapon: - """Wrapper for DCS weapons.""" - - #: The CLSID used by DCS. - clsid: str - - #: The group this weapon belongs to. - weapon_group: WeaponGroup = field(compare=False) - - _by_clsid: ClassVar[dict[str, Weapon]] = {} - _loaded: ClassVar[bool] = False - - def __str__(self) -> str: - return self.name - - @cached_property - def pydcs_data(self) -> PydcsWeapon: - if self.clsid == "": - # Special case for a "weapon" that isn't exposed by pydcs. - return { - "clsid": self.clsid, - "name": "Clean", - "weight": 0, - } - return weapon_ids[self.clsid] - - @property - def name(self) -> str: - return self.pydcs_data["name"] - - def __setstate__(self, state: dict[str, Any]) -> None: - # Update any existing models with new data on load. - updated = Weapon.with_clsid(state["clsid"]) - state.update(updated.__dict__) - self.__dict__.update(state) - - @classmethod - def register(cls, weapon: Weapon) -> None: - if weapon.clsid in cls._by_clsid: - duplicate = cls._by_clsid[weapon.clsid] - raise ValueError( - "Weapon CLSID used in more than one weapon type: " - f"{duplicate.name} and {weapon.name}: {weapon.clsid}" - ) - cls._by_clsid[weapon.clsid] = weapon - - @classmethod - def with_clsid(cls, clsid: str) -> Weapon: - if not cls._loaded: - cls._load_all() - return cls._by_clsid[clsid] - - @classmethod - def _load_all(cls) -> None: - WeaponGroup.load_all() - cls._loaded = True - - def available_on(self, date: datetime.date) -> bool: - introduction_year = self.weapon_group.introduction_year - if introduction_year is None: - return True - return date >= datetime.date(introduction_year, 1, 1) - - @property - def fallbacks(self) -> Iterator[Weapon]: - yield self - fallback: Optional[WeaponGroup] = self.weapon_group - while fallback is not None: - yield from fallback.weapons - fallback = fallback.fallback - - -@unique -class WeaponType(Enum): - ARM = "ARM" - LGB = "LGB" - TGP = "TGP" - DECOY = "decoy" - UNKNOWN = "unknown" - - -@dataclass(frozen=True) -class WeaponGroup: - """Group of "identical" weapons loaded from resources/weapons. - - DCS has multiple unique "weapons" for each type of weapon. There are four distinct - class IDs for the AIM-7M, some unique to certain aircraft. We group them in the - resources to make year/fallback data easier to track. - """ - - #: The name of the weapon group in the resource file. - name: str - - #: The type of the weapon group. - type: WeaponType = field(compare=False) - - #: The year of introduction. - introduction_year: Optional[int] = field(compare=False) - - #: The name of the fallback weapon group. - fallback_name: Optional[str] = field(compare=False) - - #: The specific weapons that belong to this weapon group. - weapons: list[Weapon] = field(init=False, default_factory=list) - - _by_name: ClassVar[dict[str, WeaponGroup]] = {} - _loaded: ClassVar[bool] = False - - def __str__(self) -> str: - return self.name - - @property - def fallback(self) -> Optional[WeaponGroup]: - if self.fallback_name is None: - return None - return WeaponGroup.named(self.fallback_name) - - def __setstate__(self, state: dict[str, Any]) -> None: - # Update any existing models with new data on load. - updated = WeaponGroup.named(state["name"]) - state.update(updated.__dict__) - self.__dict__.update(state) - - @classmethod - def register(cls, group: WeaponGroup) -> None: - if group.name in cls._by_name: - duplicate = cls._by_name[group.name] - raise ValueError( - "Weapon group name used in more than one weapon type: " - f"{duplicate.name} and {group.name}" - ) - cls._by_name[group.name] = group - - @classmethod - def named(cls, name: str) -> WeaponGroup: - if not cls._loaded: - cls.load_all() - return cls._by_name[name] - - @classmethod - def _each_weapon_group(cls) -> Iterator[WeaponGroup]: - for group_file_path in Path("resources/weapons").glob("**/*.yaml"): - with group_file_path.open(encoding="utf8") as group_file: - data = yaml.safe_load(group_file) - name = data["name"] - try: - weapon_type = WeaponType(data["type"]) - except KeyError: - weapon_type = WeaponType.UNKNOWN - year = data.get("year") - fallback_name = data.get("fallback") - group = WeaponGroup(name, weapon_type, year, fallback_name) - for clsid in data["clsids"]: - weapon = Weapon(clsid, group) - Weapon.register(weapon) - group.weapons.append(weapon) - yield group - - @classmethod - def register_clean_pylon(cls) -> None: - group = WeaponGroup( - "Clean pylon", - type=WeaponType.UNKNOWN, - introduction_year=None, - fallback_name=None, - ) - cls.register(group) - weapon = Weapon("", group) - Weapon.register(weapon) - group.weapons.append(weapon) - - @classmethod - def register_unknown_weapons(cls, seen_clsids: set[str]) -> None: - unknown_weapons = set(weapon_ids.keys()) - seen_clsids - group = WeaponGroup( - "Unknown", - type=WeaponType.UNKNOWN, - introduction_year=None, - fallback_name=None, - ) - cls.register(group) - for clsid in unknown_weapons: - weapon = Weapon(clsid, group) - Weapon.register(weapon) - group.weapons.append(weapon) - - @classmethod - def load_all(cls) -> None: - if cls._loaded: - return - seen_clsids: set[str] = set() - for group in cls._each_weapon_group(): - cls.register(group) - seen_clsids.update(w.clsid for w in group.weapons) - cls.register_clean_pylon() - cls.register_unknown_weapons(seen_clsids) - cls._loaded = True - - -@dataclass(frozen=True) -class Pylon: - number: int - allowed: set[Weapon] - - def can_equip(self, weapon: Weapon) -> bool: - # TODO: Fix pydcs to support the "weapon". - # is a special case because pydcs doesn't know about that "weapon", so - # it's not compatible with *any* pylon. Just trust the loadout and try to equip - # it. - # - # A similar hack exists in QPylonEditor to forcibly add "Clean" to the list of - # valid configurations for that pylon if a loadout has been seen with that - # configuration. - return weapon in self.allowed or weapon.clsid == "" - - def equip(self, unit: FlyingUnit, weapon: Weapon) -> None: - if not self.can_equip(weapon): - logging.error(f"Pylon {self.number} cannot equip {weapon.name}") - unit.load_pylon(self.make_pydcs_assignment(weapon), self.number) - - def make_pydcs_assignment(self, weapon: Weapon) -> PydcsWeaponAssignment: - return self.number, weapon.pydcs_data - - def available_on(self, date: datetime.date) -> Iterator[Weapon]: - for weapon in self.allowed: - if weapon.available_on(date): - yield weapon - - @classmethod - def for_aircraft(cls, aircraft: AircraftType, number: int) -> Pylon: - # In pydcs these are all arbitrary inner classes of the aircraft type. - # The only way to identify them is by their name. - pylons = [ - v - for v in aircraft.dcs_unit_type.__dict__.values() - if inspect.isclass(v) and v.__name__.startswith("Pylon") - ] - - # And that Pylon class has members with irrelevant names that have - # values of (pylon number, allowed weapon). - allowed = set() - for pylon in pylons: - for key, value in pylon.__dict__.items(): - if key.startswith("__"): - continue - pylon_number, weapon = value - if pylon_number != number: - continue - allowed.add(Weapon.with_clsid(weapon["clsid"])) - - return cls(number, allowed) - - @classmethod - def iter_pylons(cls, aircraft: AircraftType) -> Iterator[Pylon]: - for pylon in sorted(list(aircraft.dcs_unit_type.pylons)): - yield cls.for_aircraft(aircraft, pylon) diff --git a/game/db/__init__.py b/game/db/__init__.py deleted file mode 100644 index 86aeff928..000000000 --- a/game/db/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .database import Database -from .gamedb import GameDb diff --git a/game/db/database.py b/game/db/database.py deleted file mode 100644 index 319f70e9f..000000000 --- a/game/db/database.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Generic, TypeVar -from uuid import UUID - -T = TypeVar("T") - - -class Database(Generic[T]): - def __init__(self) -> None: - self.objects: dict[UUID, T] = {} - - def add(self, uuid: UUID, obj: T) -> None: - if uuid in self.objects: - raise KeyError(f"Object with UUID {uuid} already exists") - self.objects[uuid] = obj - - def get(self, uuid: UUID) -> T: - return self.objects[uuid] - - def remove(self, uuid: UUID) -> None: - del self.objects[uuid] diff --git a/game/db/gamedb.py b/game/db/gamedb.py deleted file mode 100644 index 04a084de6..000000000 --- a/game/db/gamedb.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import TYPE_CHECKING - -from .database import Database - -if TYPE_CHECKING: - from game.ato import Flight - from game.theater import FrontLine, TheaterGroundObject - - -class GameDb: - def __init__(self) -> None: - self.flights: Database[Flight] = Database() - self.front_lines: Database[FrontLine] = Database() - self.tgos: Database[TheaterGroundObject] = Database() diff --git a/game/dcs/__init__.py b/game/dcs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/dcs/aircrafttype.py b/game/dcs/aircrafttype.py deleted file mode 100644 index 610e7bc42..000000000 --- a/game/dcs/aircrafttype.py +++ /dev/null @@ -1,524 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from dataclasses import dataclass, replace as dataclasses_replace -from functools import cache, cached_property -from pathlib import Path -from typing import Any, ClassVar, Dict, Iterator, Optional, TYPE_CHECKING, Type - -from dcs.helicopters import helicopter_map -from dcs.planes import plane_map -from dcs.unitpropertydescription import UnitPropertyDescription -from dcs.unittype import FlyingType - -from game.data.units import UnitClass -from game.dcs.lasercodeconfig import LaserCodeConfig -from game.dcs.unittype import UnitType -from game.radio.channels import ( - ApacheChannelNamer, - ChannelNamer, - CommonRadioChannelAllocator, - FarmerRadioChannelAllocator, - HueyChannelNamer, - LegacyWarthogChannelNamer, - MirageChannelNamer, - MirageF1CEChannelNamer, - NoOpChannelAllocator, - RadioChannelAllocator, - SCR522ChannelNamer, - SCR522RadioChannelAllocator, - SingleRadioChannelNamer, - TomcatChannelNamer, - ViggenChannelNamer, - ViggenRadioChannelAllocator, - ViperChannelNamer, - WarthogChannelNamer, -) -from game.utils import ( - Distance, - ImperialUnits, - MetricUnits, - NauticalUnits, - SPEED_OF_SOUND_AT_SEA_LEVEL, - Speed, - UnitSystem, - feet, - knots, - kph, - nautical_miles, -) - -if TYPE_CHECKING: - from game.ato import FlightType - from game.missiongenerator.aircraft.flightdata import FlightData - from game.missiongenerator.missiondata import MissionData - from game.radio.radios import Radio, RadioFrequency, RadioRegistry - - -@dataclass(frozen=True) -class RadioConfig: - inter_flight: Optional[Radio] - intra_flight: Optional[Radio] - channel_allocator: Optional[RadioChannelAllocator] - channel_namer: Type[ChannelNamer] - - @classmethod - def from_data(cls, data: dict[str, Any]) -> RadioConfig: - return RadioConfig( - cls.make_radio(data.get("inter_flight", None)), - cls.make_radio(data.get("intra_flight", None)), - cls.make_allocator(data.get("channels", {})), - cls.make_namer(data.get("channels", {})), - ) - - @classmethod - def make_radio(cls, name: Optional[str]) -> Optional[Radio]: - from game.radio.radios import get_radio - - if name is None: - return None - return get_radio(name) - - @classmethod - def make_allocator(cls, data: dict[str, Any]) -> Optional[RadioChannelAllocator]: - try: - alloc_type = data["type"] - except KeyError: - return None - allocator_type: Type[RadioChannelAllocator] = { - "SCR-522": SCR522RadioChannelAllocator, - "common": CommonRadioChannelAllocator, - "farmer": FarmerRadioChannelAllocator, - "noop": NoOpChannelAllocator, - "viggen": ViggenRadioChannelAllocator, - }[alloc_type] - return allocator_type.from_cfg(data) - - @classmethod - def make_namer(cls, config: dict[str, Any]) -> Type[ChannelNamer]: - return { - "SCR-522": SCR522ChannelNamer, - "default": ChannelNamer, - "huey": HueyChannelNamer, - "mirage": MirageChannelNamer, - "mirage-f1ce": MirageF1CEChannelNamer, - "single": SingleRadioChannelNamer, - "tomcat": TomcatChannelNamer, - "viggen": ViggenChannelNamer, - "viper": ViperChannelNamer, - "apache": ApacheChannelNamer, - "a10c-legacy": LegacyWarthogChannelNamer, - "a10c-ii": WarthogChannelNamer, - }[config.get("namer", "default")] - - -@dataclass(frozen=True) -class PatrolConfig: - altitude: Optional[Distance] - speed: Optional[Speed] - - @classmethod - def from_data(cls, data: dict[str, Any]) -> PatrolConfig: - altitude = data.get("altitude", None) - speed = data.get("speed", None) - return PatrolConfig( - feet(altitude) if altitude is not None else None, - knots(speed) if speed is not None else None, - ) - - -@dataclass(frozen=True) -class FuelConsumption: - #: The estimated taxi fuel requirement, in pounds. - taxi: int - - #: The estimated fuel consumption for a takeoff climb, in pounds per nautical mile. - climb: float - - #: The estimated fuel consumption for cruising, in pounds per nautical mile. - cruise: float - - #: The estimated fuel consumption for combat speeds, in pounds per nautical mile. - combat: float - - #: The minimum amount of fuel that the aircraft should land with, in pounds. This is - #: a reserve amount for landing delays or emergencies. - min_safe: int - - @classmethod - def from_data(cls, data: dict[str, Any]) -> FuelConsumption: - return FuelConsumption( - int(data["taxi"]), - float(data["climb_ppm"]), - float(data["cruise_ppm"]), - float(data["combat_ppm"]), - int(data["min_safe"]), - ) - - -# TODO: Split into PlaneType and HelicopterType? -@dataclass(frozen=True) -class AircraftType(UnitType[Type[FlyingType]]): - carrier_capable: bool - lha_capable: bool - always_keeps_gun: bool - - # If true, the aircraft does not use the guns as the last resort weapons, but as a - # main weapon. It'll RTB when it doesn't have gun ammo left. - gunfighter: bool - - # UnitSystem to use for the kneeboard, defaults to Nautical (kt/nm/ft) - kneeboard_units: UnitSystem - - # If true, kneeboards will display zulu times - utc_kneeboard: bool - - max_group_size: int - patrol_altitude: Optional[Distance] - patrol_speed: Optional[Speed] - - #: The maximum range between the origin airfield and the target for which the auto- - #: planner will consider this aircraft usable for a mission. - max_mission_range: Distance - - #: Speed used for TOT calculations - cruise_speed: Optional[Speed] - - fuel_consumption: Optional[FuelConsumption] - - default_livery: Optional[str] - - intra_flight_radio: Optional[Radio] - channel_allocator: Optional[RadioChannelAllocator] - channel_namer: Type[ChannelNamer] - - # Logisitcs info - # cabin_size defines how many troops can be loaded. 0 means the aircraft can not - # transport any troops. Default for helos is 10, non helos will have 0. - cabin_size: int - # If the aircraft can carry crates can_carry_crates should be set to true which - # will be set to true for helos by default - can_carry_crates: bool - - task_priorities: dict[FlightType, int] - - # Set to True when aircraft mounts a targeting pod by default i.e. the pod does - # not take up a weapons station. If True, do not replace LGBs with dumb bombs - # when no TGP is mounted on any station. - has_built_in_target_pod: bool - - laser_code_configs: list[LaserCodeConfig] - - use_f15e_waypoint_names: bool - - _by_name: ClassVar[dict[str, AircraftType]] = {} - _by_unit_type: ClassVar[dict[type[FlyingType], list[AircraftType]]] = defaultdict( - list - ) - - @classmethod - def register(cls, unit_type: AircraftType) -> None: - cls._by_name[unit_type.variant_id] = unit_type - cls._by_unit_type[unit_type.dcs_unit_type].append(unit_type) - - @property - def flyable(self) -> bool: - return self.dcs_unit_type.flyable - - @property - def helicopter(self) -> bool: - return self.dcs_unit_type.helicopter - - @cached_property - def max_speed(self) -> Speed: - return kph(self.dcs_unit_type.max_speed) - - @property - def preferred_patrol_altitude(self) -> Distance: - if self.patrol_altitude is not None: - return self.patrol_altitude - else: - # Estimate based on max speed. - # Aircaft with max speed 600 kph will prefer patrol at 10 000 ft - # Aircraft with max speed 2800 kph will prefer pratrol at 33 000 ft - altitude_for_lowest_speed = feet(10 * 1000) - altitude_for_highest_speed = feet(33 * 1000) - lowest_speed = kph(600) - highest_speed = kph(2800) - factor = (self.max_speed - lowest_speed).kph / ( - highest_speed - lowest_speed - ).kph - altitude = ( - altitude_for_lowest_speed - + (altitude_for_highest_speed - altitude_for_lowest_speed) * factor - ) - logging.debug( - f"Preferred patrol altitude for {self.dcs_unit_type.id}: {altitude.feet}" - ) - rounded_altitude = feet(round(1000 * round(altitude.feet / 1000))) - return max( - altitude_for_lowest_speed, - min(altitude_for_highest_speed, rounded_altitude), - ) - - def preferred_patrol_speed(self, altitude: Distance) -> Speed: - """Preferred true airspeed when patrolling""" - if self.patrol_speed is not None: - return self.patrol_speed - else: - # Estimate based on max speed. - max_speed = self.max_speed - if max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 1.6: - # Fast airplanes, should manage pretty high patrol speed - return ( - Speed.from_mach(0.85, altitude) - if altitude.feet > 20000 - else Speed.from_mach(0.7, altitude) - ) - elif max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 1.2: - # Medium-fast like F/A-18C - return ( - Speed.from_mach(0.8, altitude) - if altitude.feet > 20000 - else Speed.from_mach(0.65, altitude) - ) - elif max_speed > SPEED_OF_SOUND_AT_SEA_LEVEL * 0.7: - # Semi-fast like airliners or similar - return ( - Speed.from_mach(0.5, altitude) - if altitude.feet > 20000 - else Speed.from_mach(0.4, altitude) - ) - else: - # Slow like warbirds or helicopters - # Use whichever is slowest - mach 0.35 or 70% of max speed - logging.debug( - f"{self.display_name} max_speed * 0.7 is {max_speed * 0.7}" - ) - return min(Speed.from_mach(0.35, altitude), max_speed * 0.7) - - def alloc_flight_radio(self, radio_registry: RadioRegistry) -> RadioFrequency: - from game.radio.radios import ChannelInUseError, kHz - - if self.intra_flight_radio is not None: - return radio_registry.alloc_for_radio(self.intra_flight_radio) - - # The default radio frequency is set in megahertz. For some aircraft, it is a - # floating point value. For all current aircraft, adjusting to kilohertz will be - # sufficient to convert to an integer. - in_khz = float(self.dcs_unit_type.radio_frequency) * 1000 - if not in_khz.is_integer(): - logging.warning( - f"Found unexpected sub-kHz default radio for {self}: {in_khz} kHz. " - "Truncating to integer. The truncated frequency may not be valid for " - "the aircraft." - ) - - freq = kHz(int(in_khz)) - try: - radio_registry.reserve(freq) - except ChannelInUseError: - pass - return freq - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - if self.channel_allocator is not None: - self.channel_allocator.assign_channels_for_flight(flight, mission_data) - - def channel_name(self, radio_id: int, channel_id: int) -> str: - return self.channel_namer.channel_name(radio_id, channel_id) - - @cached_property - def laser_code_prop_ids(self) -> set[str]: - laser_code_props: set[str] = set() - for laser_code_config in self.laser_code_configs: - laser_code_props.update(laser_code_config.iter_prop_ids()) - return laser_code_props - - def iter_props(self) -> Iterator[UnitPropertyDescription]: - yield from self.dcs_unit_type.properties.values() - - def should_show_prop(self, prop_id: str) -> bool: - return prop_id not in self.laser_code_prop_ids - - def capable_of(self, task: FlightType) -> bool: - return task in self.task_priorities - - def task_priority(self, task: FlightType) -> int: - return self.task_priorities[task] - - def __setstate__(self, state: dict[str, Any]) -> None: - # Update any existing models with new data on load. - updated = AircraftType.named(state["variant_id"]) - state.update(updated.__dict__) - self.__dict__.update(state) - - @classmethod - def named(cls, name: str) -> AircraftType: - if not cls._loaded: - cls._load_all() - return cls._by_name[name] - - @classmethod - def for_dcs_type(cls, dcs_unit_type: Type[FlyingType]) -> Iterator[AircraftType]: - if not cls._loaded: - cls._load_all() - yield from cls._by_unit_type[dcs_unit_type] - - @classmethod - def iter_all(cls) -> Iterator[AircraftType]: - if not cls._loaded: - cls._load_all() - yield from cls._by_name.values() - - @classmethod - @cache - def priority_list_for_task(cls, task: FlightType) -> list[AircraftType]: - capable = [] - for aircraft in cls.iter_all(): - if aircraft.capable_of(task): - capable.append(aircraft) - return list(reversed(sorted(capable, key=lambda a: a.task_priority(task)))) - - def iter_task_capabilities(self) -> Iterator[FlightType]: - yield from self.task_priorities - - @staticmethod - def each_dcs_type() -> Iterator[Type[FlyingType]]: - yield from helicopter_map.values() - yield from plane_map.values() - - @staticmethod - def _set_props_overrides( - config: Dict[str, Any], aircraft: Type[FlyingType] - ) -> None: - if aircraft.property_defaults is None: - logging.warning( - f"'{aircraft.id}' attempted to set default prop that does not exist." - ) - else: - for k in config: - if k in aircraft.property_defaults: - aircraft.property_defaults[k] = config[k] - # In addition to setting the property_defaults, we have to set the "default" property in the - # value of aircraft.properties for the key, as this is used in parts of the codebase to get - # the default value. - aircraft.properties[k] = dataclasses_replace( - aircraft.properties[k], default=config[k] - ) - else: - logging.warning( - f"'{aircraft.id}' attempted to set default prop '{k}' that does not exist" - ) - - @classmethod - def _data_directory(cls) -> Path: - return Path("resources/units/aircraft") - - @classmethod - def _variant_from_dict( - cls, aircraft: Type[FlyingType], variant_id: str, data: dict[str, Any] - ) -> AircraftType: - from game.ato.flighttype import FlightType - - try: - price = data["price"] - except KeyError as ex: - raise KeyError(f"Missing required price field") from ex - - radio_config = RadioConfig.from_data(data.get("radios", {})) - patrol_config = PatrolConfig.from_data(data.get("patrol", {})) - - try: - mission_range = nautical_miles(int(data["max_range"])) - except (KeyError, ValueError): - mission_range = ( - nautical_miles(50) if aircraft.helicopter else nautical_miles(150) - ) - logging.warning( - f"{aircraft.id} does not specify a max_range. Defaulting to " - f"{mission_range.nautical_miles}NM" - ) - - fuel_data = data.get("fuel") - if fuel_data is not None: - fuel_consumption: Optional[FuelConsumption] = FuelConsumption.from_data( - fuel_data - ) - else: - fuel_consumption = None - - try: - introduction = data["introduced"] - if introduction is None: - introduction = "N/A" - except KeyError: - introduction = "No data." - - units_data = data.get("kneeboard_units", "nautical").lower() - units: UnitSystem = NauticalUnits() - if units_data == "imperial": - units = ImperialUnits() - if units_data == "metric": - units = MetricUnits() - - class_name = data.get("class") - unit_class = UnitClass.PLANE if class_name is None else UnitClass(class_name) - - prop_overrides = data.get("default_overrides") - if prop_overrides is not None: - cls._set_props_overrides(prop_overrides, aircraft) - - task_priorities: dict[FlightType, int] = {} - for task_name, priority in data.get("tasks", {}).items(): - task_priorities[FlightType(task_name)] = priority - - display_name = data.get("display_name", variant_id) - return AircraftType( - dcs_unit_type=aircraft, - variant_id=variant_id, - display_name=display_name, - description=data.get( - "description", - f"No data. Google {display_name}", - ), - year_introduced=introduction, - country_of_origin=data.get("origin", "No data."), - manufacturer=data.get("manufacturer", "No data."), - role=data.get("role", "No data."), - price=price, - carrier_capable=data.get("carrier_capable", False), - lha_capable=data.get("lha_capable", False), - always_keeps_gun=data.get("always_keeps_gun", False), - gunfighter=data.get("gunfighter", False), - max_group_size=data.get("max_group_size", aircraft.group_size_max), - patrol_altitude=patrol_config.altitude, - patrol_speed=patrol_config.speed, - max_mission_range=mission_range, - cruise_speed=knots(data["cruise_speed_kt_indicated"]) - if "cruise_speed_kt_indicated" in data - else None, - fuel_consumption=fuel_consumption, - default_livery=data.get("default_livery"), - intra_flight_radio=radio_config.intra_flight, - channel_allocator=radio_config.channel_allocator, - channel_namer=radio_config.channel_namer, - kneeboard_units=units, - utc_kneeboard=data.get("utc_kneeboard", False), - unit_class=unit_class, - cabin_size=data.get("cabin_size", 10 if aircraft.helicopter else 0), - can_carry_crates=data.get("can_carry_crates", aircraft.helicopter), - task_priorities=task_priorities, - has_built_in_target_pod=data.get("has_built_in_target_pod", False), - laser_code_configs=[ - LaserCodeConfig.from_yaml(d) for d in data.get("laser_codes", []) - ], - use_f15e_waypoint_names=data.get("use_f15e_waypoint_names", False), - hit_points=data.get("hit_points", 1), - ) - - def __hash__(self) -> int: - return hash(self.variant_id) diff --git a/game/dcs/beacons.py b/game/dcs/beacons.py deleted file mode 100644 index 04b96ddc1..000000000 --- a/game/dcs/beacons.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import json -from collections.abc import Iterator -from dataclasses import dataclass -from enum import IntEnum -from pathlib import Path -from typing import Optional, TYPE_CHECKING - -from game.radio.radios import RadioFrequency -from game.radio.tacan import TacanBand, TacanChannel - -if TYPE_CHECKING: - from game.theater import ConflictTheater - -BEACONS_RESOURCE_PATH = Path("resources/dcs/beacons") - - -class BeaconType(IntEnum): - BEACON_TYPE_NULL = 0 - BEACON_TYPE_VOR = 1 - BEACON_TYPE_DME = 2 - BEACON_TYPE_VOR_DME = 3 - BEACON_TYPE_TACAN = 4 - BEACON_TYPE_VORTAC = 5 - BEACON_TYPE_RSBN = 6 - BEACON_TYPE_BROADCAST_STATION = 7 - - BEACON_TYPE_HOMER = 8 - BEACON_TYPE_AIRPORT_HOMER = 9 - BEACON_TYPE_AIRPORT_HOMER_WITH_MARKER = 10 - BEACON_TYPE_ILS_FAR_HOMER = 11 - BEACON_TYPE_ILS_NEAR_HOMER = 12 - - BEACON_TYPE_ILS_LOCALIZER = 13 - BEACON_TYPE_ILS_GLIDESLOPE = 14 - - BEACON_TYPE_PRMG_LOCALIZER = 15 - BEACON_TYPE_PRMG_GLIDESLOPE = 16 - - BEACON_TYPE_ICLS_LOCALIZER = 17 - BEACON_TYPE_ICLS_GLIDESLOPE = 18 - - BEACON_TYPE_NAUTICAL_HOMER = 19 - - -@dataclass(frozen=True) -class Beacon: - name: str - callsign: str - beacon_type: BeaconType - hertz: int - channel: Optional[int] - - @property - def frequency(self) -> RadioFrequency: - return RadioFrequency(self.hertz) - - @property - def is_tacan(self) -> bool: - return self.beacon_type in ( - BeaconType.BEACON_TYPE_VORTAC, - BeaconType.BEACON_TYPE_TACAN, - ) - - @property - def tacan_channel(self) -> TacanChannel: - assert self.is_tacan - assert self.channel is not None - return TacanChannel(self.channel, TacanBand.X) - - -class Beacons: - _by_terrain: dict[str, dict[str, Beacon]] = {} - - @classmethod - def _load_for_theater_if_needed(cls, theater: ConflictTheater) -> None: - if theater.terrain.name in cls._by_terrain: - return - - beacons_file = BEACONS_RESOURCE_PATH / f"{theater.terrain.name.lower()}.json" - if not beacons_file.exists(): - raise RuntimeError(f"Beacon file {beacons_file.resolve()} is missing") - - beacons = {} - for bid, beacon in json.loads(beacons_file.read_text()).items(): - beacons[bid] = Beacon( - name=beacon["name"], - callsign=beacon["callsign"], - beacon_type=BeaconType(beacon["beacon_type"]), - hertz=beacon["hertz"], - channel=beacon["channel"], - ) - cls._by_terrain[theater.terrain.name] = beacons - - @classmethod - def _dict_for_theater(cls, theater: ConflictTheater) -> dict[str, Beacon]: - cls._load_for_theater_if_needed(theater) - return cls._by_terrain[theater.terrain.name] - - @classmethod - def iter_theater(cls, theater: ConflictTheater) -> Iterator[Beacon]: - yield from cls._dict_for_theater(theater).values() - - @classmethod - def with_id(cls, beacon_id: str, theater: ConflictTheater) -> Beacon: - return cls._dict_for_theater(theater)[beacon_id] diff --git a/game/dcs/groundunittype.py b/game/dcs/groundunittype.py deleted file mode 100644 index c44eee219..000000000 --- a/game/dcs/groundunittype.py +++ /dev/null @@ -1,137 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from dataclasses import dataclass -from pathlib import Path -from typing import Any, ClassVar, Iterator, Optional, Type - -from dcs.unittype import VehicleType -from dcs.vehicles import vehicle_map - -from game.data.units import UnitClass -from game.dcs.unittype import UnitType - - -@dataclass -class SkynetProperties: - can_engage_harm: Optional[str] = None - can_engage_air_weapon: Optional[str] = None - go_live_range_in_percent: Optional[str] = None - engagement_zone: Optional[str] = None - autonomous_behaviour: Optional[str] = None - harm_detection_chance: Optional[str] = None - - @classmethod - def from_data(cls, data: dict[str, Any]) -> SkynetProperties: - props = SkynetProperties() - if "can_engage_harm" in data: - props.can_engage_harm = str(data["can_engage_harm"]).lower() - if "can_engage_air_weapon" in data: - props.can_engage_air_weapon = str(data["can_engage_air_weapon"]).lower() - if "go_live_range_in_percent" in data: - props.go_live_range_in_percent = str(data["go_live_range_in_percent"]) - if "engagement_zone" in data: - props.engagement_zone = str(data["engagement_zone"]) - if "autonomous_behaviour" in data: - props.autonomous_behaviour = str(data["autonomous_behaviour"]) - if "harm_detection_chance" in data: - props.harm_detection_chance = str(data["harm_detection_chance"]) - return props - - def to_dict(self) -> dict[str, str]: - properties: dict[str, str] = {} - for key, value in self.__dict__.items(): - if value is not None: - properties[key] = value - return properties - - def __hash__(self) -> int: - return hash(id(self)) - - -@dataclass(frozen=True) -class GroundUnitType(UnitType[Type[VehicleType]]): - spawn_weight: int - skynet_properties: SkynetProperties - - # Defines if we should place the ground unit with an inverted heading. - # Some units like few Launchers have to be placed backwards to be able to fire. - reversed_heading: bool = False - - _by_name: ClassVar[dict[str, GroundUnitType]] = {} - _by_unit_type: ClassVar[ - dict[type[VehicleType], list[GroundUnitType]] - ] = defaultdict(list) - - def __setstate__(self, state: dict[str, Any]) -> None: - # Update any existing models with new data on load. - updated = GroundUnitType.named(state["variant_id"]) - state.update(updated.__dict__) - self.__dict__.update(state) - - @classmethod - def register(cls, unit_type: GroundUnitType) -> None: - cls._by_name[unit_type.variant_id] = unit_type - cls._by_unit_type[unit_type.dcs_unit_type].append(unit_type) - - @classmethod - def named(cls, name: str) -> GroundUnitType: - if not cls._loaded: - cls._load_all() - return cls._by_name[name] - - @classmethod - def for_dcs_type(cls, dcs_unit_type: Type[VehicleType]) -> Iterator[GroundUnitType]: - if not cls._loaded: - cls._load_all() - yield from cls._by_unit_type[dcs_unit_type] - - @staticmethod - def each_dcs_type() -> Iterator[Type[VehicleType]]: - yield from vehicle_map.values() - - @classmethod - def _data_directory(cls) -> Path: - return Path("resources/units/ground_units") - - @classmethod - def _variant_from_dict( - cls, vehicle: Type[VehicleType], variant_id: str, data: dict[str, Any] - ) -> GroundUnitType: - try: - introduction = data["introduced"] - if introduction is None: - introduction = "N/A" - except KeyError: - introduction = "No data." - - class_name = data.get("class") - if class_name is None: - logging.warning(f"{vehicle.id} has no class") - unit_class = UnitClass.UNKNOWN - else: - unit_class = UnitClass(class_name) - - display_name = data.get("display_name", variant_id) - return GroundUnitType( - dcs_unit_type=vehicle, - unit_class=unit_class, - spawn_weight=data.get("spawn_weight", 0), - variant_id=variant_id, - display_name=display_name, - description=data.get( - "description", - f"No data. Google {display_name}", - ), - year_introduced=introduction, - country_of_origin=data.get("origin", "No data."), - manufacturer=data.get("manufacturer", "No data."), - role=data.get("role", "No data."), - price=data.get("price", 1), - skynet_properties=SkynetProperties.from_data( - data.get("skynet_properties", {}) - ), - reversed_heading=data.get("reversed_heading", False), - hit_points=data.get("hit_points", 1), - ) diff --git a/game/dcs/helpers.py b/game/dcs/helpers.py deleted file mode 100644 index b8bcb7518..000000000 --- a/game/dcs/helpers.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Optional, Type - -from dcs.helicopters import helicopter_map -from dcs.planes import plane_map -from dcs.ships import ship_map -from dcs.unittype import UnitType -from dcs.vehicles import vehicle_map -from dcs.statics import fortification_map, groundobject_map, warehouse_map, cargo_map - - -def unit_type_from_name(name: str) -> Optional[Type[UnitType]]: - if name in vehicle_map: - return vehicle_map[name] - elif name in plane_map: - return plane_map[name] - elif name in ship_map: - return ship_map[name] - if name in helicopter_map: - return helicopter_map[name] - else: - # Try statics - return static_type_from_name(name) - - -def static_type_from_name(name: str) -> Optional[Type[UnitType]]: - if name in fortification_map: - return fortification_map[name] - elif name in groundobject_map: - return groundobject_map[name] - elif name in warehouse_map: - return warehouse_map[name] - if name in cargo_map: - return cargo_map[name] - else: - return None diff --git a/game/dcs/lasercodeconfig.py b/game/dcs/lasercodeconfig.py deleted file mode 100644 index 01c63fe29..000000000 --- a/game/dcs/lasercodeconfig.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections.abc import Iterator -from typing import Any - - -class LaserCodeConfig(ABC): - @staticmethod - def from_yaml(data: dict[str, Any]) -> LaserCodeConfig: - if (property_def := data.get("property")) is not None: - return SinglePropertyLaserCodeConfig( - property_def["id"], int(property_def["digits"]) - ) - return MultiplePropertyLaserCodeConfig( - [(d["id"], d["digit"]) for d in data["properties"]] - ) - - @abstractmethod - def iter_prop_ids(self) -> Iterator[str]: - ... - - @abstractmethod - def property_dict_for_code(self, code: int) -> dict[str, int]: - ... - - -class SinglePropertyLaserCodeConfig(LaserCodeConfig): - def __init__(self, property_id: str, digits: int) -> None: - self.property_id = property_id - self.digits = digits - - def iter_prop_ids(self) -> Iterator[str]: - yield self.property_id - - def property_dict_for_code(self, code: int) -> dict[str, int]: - return {self.property_id: code % 10**self.digits} - - -class MultiplePropertyLaserCodeConfig(LaserCodeConfig): - def __init__(self, property_digit_mappings: list[tuple[str, int]]) -> None: - self.property_digit_mappings = property_digit_mappings - - def iter_prop_ids(self) -> Iterator[str]: - yield from (i for i, p in self.property_digit_mappings) - - def property_dict_for_code(self, code: int) -> dict[str, int]: - d = {} - for prop_id, idx in self.property_digit_mappings: - d[prop_id] = code // 10**idx % 10 - return d diff --git a/game/dcs/propertyvalue.py b/game/dcs/propertyvalue.py deleted file mode 100644 index 6a31cbac5..000000000 --- a/game/dcs/propertyvalue.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Generic, TypeVar - -ValueT = TypeVar("ValueT", bool, int) - - -@dataclass(frozen=True) -class PropertyValue(Generic[ValueT]): - id: str - value: ValueT diff --git a/game/dcs/shipunittype.py b/game/dcs/shipunittype.py deleted file mode 100644 index 71cbd3df3..000000000 --- a/game/dcs/shipunittype.py +++ /dev/null @@ -1,83 +0,0 @@ -from __future__ import annotations - -from collections import defaultdict -from dataclasses import dataclass -from pathlib import Path -from typing import ClassVar, Iterator, Type, Any - -from dcs.ships import ship_map -from dcs.unittype import ShipType - -from game.data.units import UnitClass -from game.dcs.unittype import UnitType - - -@dataclass(frozen=True) -class ShipUnitType(UnitType[Type[ShipType]]): - _by_name: ClassVar[dict[str, ShipUnitType]] = {} - _by_unit_type: ClassVar[dict[type[ShipType], list[ShipUnitType]]] = defaultdict( - list - ) - - def __setstate__(self, state: dict[str, Any]) -> None: - # Update any existing models with new data on load. - updated = ShipUnitType.named(state["variant_id"]) - state.update(updated.__dict__) - self.__dict__.update(state) - - @classmethod - def register(cls, unit_type: ShipUnitType) -> None: - cls._by_name[unit_type.variant_id] = unit_type - cls._by_unit_type[unit_type.dcs_unit_type].append(unit_type) - - @classmethod - def named(cls, name: str) -> ShipUnitType: - if not cls._loaded: - cls._load_all() - return cls._by_name[name] - - @classmethod - def for_dcs_type(cls, dcs_unit_type: Type[ShipType]) -> Iterator[ShipUnitType]: - if not cls._loaded: - cls._load_all() - yield from cls._by_unit_type[dcs_unit_type] - - @staticmethod - def each_dcs_type() -> Iterator[Type[ShipType]]: - yield from ship_map.values() - - @classmethod - def _data_directory(cls) -> Path: - return Path("resources/units/ships") - - @classmethod - def _variant_from_dict( - cls, ship: Type[ShipType], variant_id: str, data: dict[str, Any] - ) -> ShipUnitType: - try: - introduction = data["introduced"] - if introduction is None: - introduction = "N/A" - except KeyError: - introduction = "No data." - - class_name = data.get("class") - unit_class = UnitClass(class_name) - - display_name = data.get("display_name", variant_id) - return ShipUnitType( - dcs_unit_type=ship, - unit_class=unit_class, - variant_id=variant_id, - display_name=data.get("display_name", variant_id), - description=data.get( - "description", - f"No data. Google {display_name}", - ), - year_introduced=introduction, - country_of_origin=data.get("origin", "No data."), - manufacturer=data.get("manufacturer", "No data."), - role=data.get("role", "No data."), - price=data["price"], - hit_points=data.get("hit_points", 1), - ) diff --git a/game/dcs/unitproperty.py b/game/dcs/unitproperty.py deleted file mode 100644 index d87025456..000000000 --- a/game/dcs/unitproperty.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -import inspect -from collections.abc import Iterator -from dataclasses import dataclass -from typing import Any, Generic, Type, TypeVar - -from dcs.unittype import FlyingType - -from .propertyvalue import PropertyValue - -ValueT = TypeVar("ValueT", bool, int) - - -@dataclass(frozen=True) -class UnitProperty(Generic[ValueT]): - id: str - default: ValueT - values: list[PropertyValue[Any]] - - @classmethod - def for_aircraft( - cls, unit_type: Type[FlyingType] - ) -> Iterator[UnitProperty[ValueT]]: - try: - props = unit_type.Properties # type: ignore - except AttributeError: - return - - if unit_type.property_defaults is None: - raise RuntimeError(f"{unit_type} has Properties but no defaults") - - for name, attr in inspect.getmembers(props, inspect.isclass): - if name.startswith("__"): - continue - yield cls.property_from(attr, unit_type.property_defaults[name]) - - @classmethod - def property_from(cls, attr: Type[ValueT], default: ValueT) -> UnitProperty[ValueT]: - prop_id = attr.id # type: ignore - values = getattr(attr, "Values", None) - if values is None: - prop_values = list(cls.default_values_for(prop_id, default)) - else: - prop_values = [] - for name, value in inspect.getmembers(values): - if name.startswith("__"): - continue - prop_values.append(PropertyValue(name, value)) - return UnitProperty(prop_id, default, prop_values) - - @classmethod - def default_values_for( - cls, prop_id: str, default: ValueT - ) -> Iterator[PropertyValue[ValueT]]: - if isinstance(default, bool): - yield PropertyValue("True", True) - yield PropertyValue("False", False) - elif isinstance(default, int): - for i in range(10): - yield PropertyValue(str(i), i) - else: - raise TypeError( - f"Unexpected property type for {prop_id}: {default.__class__}" - ) diff --git a/game/dcs/unittype.py b/game/dcs/unittype.py deleted file mode 100644 index 01c660e6a..000000000 --- a/game/dcs/unittype.py +++ /dev/null @@ -1,101 +0,0 @@ -from __future__ import annotations - -import logging -from abc import ABC -from dataclasses import dataclass -from functools import cached_property -from pathlib import Path -from typing import ClassVar, Generic, Iterator, Self, Type, TypeVar, Any - -import yaml -from dcs.unittype import UnitType as DcsUnitType - -from game.data.units import UnitClass - -DcsUnitTypeT = TypeVar("DcsUnitTypeT", bound=Type[DcsUnitType]) - - -@dataclass(frozen=True) -class UnitType(ABC, Generic[DcsUnitTypeT]): - dcs_unit_type: DcsUnitTypeT - variant_id: str - display_name: str - description: str - year_introduced: str - country_of_origin: str - manufacturer: str - role: str - price: int - unit_class: UnitClass - hit_points: int - - _loaded: ClassVar[bool] = False - - def __str__(self) -> str: - return self.display_name - - @property - def dcs_id(self) -> str: - return self.dcs_unit_type.id - - @classmethod - def register(cls, unit_type: Self) -> None: - raise NotImplementedError - - @classmethod - def named(cls, name: str) -> Self: - raise NotImplementedError - - @classmethod - def for_dcs_type(cls, dcs_unit_type: DcsUnitTypeT) -> Iterator[Self]: - raise NotImplementedError - - @staticmethod - def each_dcs_type() -> Iterator[DcsUnitTypeT]: - raise NotImplementedError - - @classmethod - def _data_directory(cls) -> Path: - raise NotImplementedError - - @classmethod - def _each_variant_of(cls, unit: DcsUnitTypeT) -> Iterator[Self]: - data_path = cls._data_directory() / f"{unit.id}.yaml" - if not data_path.exists(): - logging.warning(f"No data for {unit.id}; it will not be available") - return - - with data_path.open(encoding="utf-8") as data_file: - data = yaml.safe_load(data_file) - - for variant_id, variant_data in data.get("variants", {unit.id: {}}).items(): - if variant_data is None: - variant_data = {} - yield cls._variant_from_dict(unit, variant_id, data | variant_data) - - @classmethod - def _variant_from_dict( - cls, dcs_unit_type: DcsUnitTypeT, variant_id: str, data: dict[str, Any] - ) -> Self: - raise NotImplementedError - - @classmethod - def _load_all(cls) -> None: - for unit_type in cls.each_dcs_type(): - for data in cls._each_variant_of(unit_type): - cls.register(data) - cls._loaded = True - - @cached_property - def eplrs_capable(self) -> bool: - return getattr(self.dcs_unit_type, "eplrs", False) - - @classmethod - def exists(cls, name: str) -> bool: - if not cls._loaded: - cls._load_all() - try: - cls.named(name) - return True - except (KeyError, AssertionError): - return False diff --git a/game/debriefing.py b/game/debriefing.py deleted file mode 100644 index 78f14e828..000000000 --- a/game/debriefing.py +++ /dev/null @@ -1,529 +0,0 @@ -from __future__ import annotations -from abc import ABC -import itertools -import logging -from collections import defaultdict -from dataclasses import dataclass, field -from typing import ( - Any, - Dict, - Iterator, - List, - Optional, - TYPE_CHECKING, - TypeVar, - Union, -) -from uuid import UUID - -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.theater import Airfield, ControlPoint - -if TYPE_CHECKING: - from game import Game - from game.ato.flight import Flight - from game.dcs.unittype import UnitType - from game.sim.simulationresults import SimulationResults - from game.transfers import CargoShip - from game.theater import TheaterUnit - from game.unitmap import ( - AirliftUnits, - ConvoyUnit, - FlyingUnit, - FrontLineUnit, - TheaterUnitMapping, - UnitMap, - SceneryObjectMapping, - ) - -DEBRIEFING_LOG_EXTENSION = "log" - - -@dataclass(frozen=True) -class AirLosses: - player: list[FlyingUnit] - enemy: list[FlyingUnit] - - @property - def losses(self) -> Iterator[FlyingUnit]: - return itertools.chain(self.player, self.enemy) - - def by_type(self, player: bool) -> Dict[AircraftType, int]: - losses_by_type: Dict[AircraftType, int] = defaultdict(int) - losses = self.player if player else self.enemy - for loss in losses: - losses_by_type[loss.flight.unit_type] += 1 - return losses_by_type - - def surviving_flight_members(self, flight: Flight) -> int: - losses = 0 - for loss in self.losses: - if loss.flight == flight: - losses += 1 - return flight.count - losses - - -@dataclass -class GroundLosses: - player_front_line: List[FrontLineUnit] = field(default_factory=list) - enemy_front_line: List[FrontLineUnit] = field(default_factory=list) - - player_convoy: List[ConvoyUnit] = field(default_factory=list) - enemy_convoy: List[ConvoyUnit] = field(default_factory=list) - - player_cargo_ships: List[CargoShip] = field(default_factory=list) - enemy_cargo_ships: List[CargoShip] = field(default_factory=list) - - player_airlifts: List[AirliftUnits] = field(default_factory=list) - enemy_airlifts: List[AirliftUnits] = field(default_factory=list) - - player_ground_objects: List[TheaterUnitMapping] = field(default_factory=list) - enemy_ground_objects: List[TheaterUnitMapping] = field(default_factory=list) - - player_scenery: List[SceneryObjectMapping] = field(default_factory=list) - enemy_scenery: List[SceneryObjectMapping] = field(default_factory=list) - - player_airfields: List[Airfield] = field(default_factory=list) - enemy_airfields: List[Airfield] = field(default_factory=list) - - -@dataclass(frozen=True) -class BaseCaptureEvent: - control_point: ControlPoint - captured_by_player: bool - - -@dataclass -class UnitHitpointUpdate(ABC): - unit: Any - hit_points: int - - @classmethod - def from_json( - cls, data: dict[str, Any], unit_map: UnitMap - ) -> Optional[UnitHitpointUpdate]: - raise NotImplementedError() - - def is_dead(self) -> bool: - # Use hit_points > 1 to indicate unit is alive, rather than >=1 (DCS logic) to account for uncontrolled units which often have a - # health floor of 1 - if self.hit_points > 1: - return False - return True - - def is_friendly(self, to_player: bool) -> bool: - raise NotImplementedError() - - -@dataclass -class FlyingUnitHitPointUpdate(UnitHitpointUpdate): - unit: FlyingUnit - - @classmethod - def from_json( - cls, data: dict[str, Any], unit_map: UnitMap - ) -> Optional[FlyingUnitHitPointUpdate]: - unit = unit_map.flight(data["name"]) - if unit is None: - return None - return cls(unit, int(float(data["hit_points"]))) - - def is_friendly(self, to_player: bool) -> bool: - if to_player: - return self.unit.flight.departure.captured - return not self.unit.flight.departure.captured - - -@dataclass -class TheaterUnitHitPointUpdate(UnitHitpointUpdate): - unit: TheaterUnitMapping - - @classmethod - def from_json( - cls, data: dict[str, Any], unit_map: UnitMap - ) -> Optional[TheaterUnitHitPointUpdate]: - unit = unit_map.theater_units(data["name"]) - if unit is None: - return None - - if unit.theater_unit.unit_type is None: - logging.debug( - f"Ground unit {data['name']} does not have a valid unit type." - ) - return None - - if unit.theater_unit.hit_points is None: - logging.debug(f"Ground unit {data['name']} does not have hit_points set.") - return None - - sim_hit_points = int( - float(data["hit_points"]) - ) # Hit points out of the sim i.e. new unit hit points - damage in this turn - previous_turn_hit_points = ( - unit.theater_unit.hit_points - ) # Hit points at the end of the previous turn - full_health_hit_points = ( - unit.theater_unit.unit_type.hit_points - ) # Hit points of a new unit - - # Hit points left after damage this turn is subtracted from hit points at the end of the previous turn - new_hit_points = previous_turn_hit_points - ( - full_health_hit_points - sim_hit_points - ) - - return cls(unit, new_hit_points) - - def is_dead(self) -> bool: - # Some TheaterUnits can start with low health of around 1, make sure we don't always kill them off. - if ( - self.unit.theater_unit.unit_type is not None - and self.unit.theater_unit.unit_type.hit_points is not None - and self.unit.theater_unit.unit_type.hit_points <= 1 - ): - return False - return super().is_dead() - - def is_friendly(self, to_player: bool) -> bool: - return self.unit.theater_unit.ground_object.is_friendly(to_player) - - def commit(self) -> None: - self.unit.theater_unit.hit_points = self.hit_points - - -@dataclass(frozen=True) -class StateData: - #: True if the mission ended. If False, the mission exited abnormally. - mission_ended: bool - - #: Names of aircraft units that were killed during the mission. - killed_aircraft: List[str] - - #: Names of vehicles, ships or buildings that were killed during the mission. - killed_ground_units: List[str] - - #: List of descriptions of destroyed statics. Format of each element is a mapping of - #: the coordinate type ("x", "y", "z", "type", "orientation") to the value. - destroyed_statics: List[dict[str, Union[float, str]]] - - #: Mangled names of bases that were captured during the mission. - base_capture_events: List[str] - - # List of descriptions of damage done to units. Each list element is a dict like the following - # {"name": "", "hit_points": } - unit_hit_point_updates: List[dict[str, Any]] - - @classmethod - def from_json(cls, data: Dict[str, Any], unit_map: UnitMap) -> StateData: - def clean_unit_list(unit_list: List[Any]) -> List[str]: - # Cleans list of units in state.json by - # - Removing duplicates. Airfields emit a new "dead" event every time a bomb - # is dropped on them when they've already dead. - # - Normalise dead map objects (which are ints) to strings. The unit map - # only stores strings - units = set() - for unit in unit_list: - units.add(str(unit)) - return list(units) - - killed_aircraft = [] - killed_ground_units = [] - - # Process killed units from S_EVENT_UNIT_LOST, S_EVENT_CRASH, S_EVENT_DEAD & S_EVENT_KILL - # Try to process every event that could indicate a unit was killed, even if it is - # inefficient and results in duplication as the logic DCS uses to trigger the various - # event types is not clear and may change over time. - killed_units = clean_unit_list( - data["unit_lost_events"] - + data["kill_events"] - + data["crash_events"] - + data["dead_events"] - + data["killed_ground_units"] - ) - for unit in killed_units: # organize killed units into aircraft vs ground - if unit_map.flight(unit) is not None: - killed_aircraft.append(unit) - else: - killed_ground_units.append(unit) - - return cls( - mission_ended=data["mission_ended"], - killed_aircraft=killed_aircraft, - killed_ground_units=killed_ground_units, - destroyed_statics=data["destroyed_objects_positions"], - base_capture_events=data["base_capture_events"], - unit_hit_point_updates=data["unit_hit_point_updates"], - ) - - -class Debriefing: - def __init__( - self, state_data: Dict[str, Any], game: Game, unit_map: UnitMap - ) -> None: - self.state_data = StateData.from_json(state_data, unit_map) - self.game = game - self.unit_map = unit_map - - self.player_country = game.blue.country_name - self.enemy_country = game.red.country_name - - self.air_losses = self.dead_aircraft() - self.ground_losses = self.dead_ground_units() - self.base_captures = self.base_capture_events() - - def merge_simulation_results(self, results: SimulationResults) -> None: - for air_loss in results.air_losses: - if air_loss.flight.squadron.player: - self.air_losses.player.append(air_loss) - else: - self.air_losses.enemy.append(air_loss) - - @property - def front_line_losses(self) -> Iterator[FrontLineUnit]: - yield from self.ground_losses.player_front_line - yield from self.ground_losses.enemy_front_line - - @property - def convoy_losses(self) -> Iterator[ConvoyUnit]: - yield from self.ground_losses.player_convoy - yield from self.ground_losses.enemy_convoy - - @property - def cargo_ship_losses(self) -> Iterator[CargoShip]: - yield from self.ground_losses.player_cargo_ships - yield from self.ground_losses.enemy_cargo_ships - - @property - def airlift_losses(self) -> Iterator[AirliftUnits]: - yield from self.ground_losses.player_airlifts - yield from self.ground_losses.enemy_airlifts - - @property - def ground_object_losses(self) -> Iterator[TheaterUnitMapping]: - yield from self.ground_losses.player_ground_objects - yield from self.ground_losses.enemy_ground_objects - - @property - def scenery_object_losses(self) -> Iterator[SceneryObjectMapping]: - yield from self.ground_losses.player_scenery - yield from self.ground_losses.enemy_scenery - - @property - def damaged_runways(self) -> Iterator[Airfield]: - yield from self.ground_losses.player_airfields - yield from self.ground_losses.enemy_airfields - - def casualty_count(self, control_point: ControlPoint) -> int: - return len([x for x in self.front_line_losses if x.origin == control_point]) - - def front_line_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]: - losses_by_type: dict[GroundUnitType, int] = defaultdict(int) - if player: - losses = self.ground_losses.player_front_line - else: - losses = self.ground_losses.enemy_front_line - for loss in losses: - losses_by_type[loss.unit_type] += 1 - return losses_by_type - - def convoy_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]: - losses_by_type: dict[GroundUnitType, int] = defaultdict(int) - if player: - losses = self.ground_losses.player_convoy - else: - losses = self.ground_losses.enemy_convoy - for loss in losses: - losses_by_type[loss.unit_type] += 1 - return losses_by_type - - def cargo_ship_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]: - losses_by_type: dict[GroundUnitType, int] = defaultdict(int) - if player: - ships = self.ground_losses.player_cargo_ships - else: - ships = self.ground_losses.enemy_cargo_ships - for ship in ships: - for unit_type, count in ship.units.items(): - losses_by_type[unit_type] += count - return losses_by_type - - def airlift_losses_by_type(self, player: bool) -> dict[GroundUnitType, int]: - losses_by_type: dict[GroundUnitType, int] = defaultdict(int) - if player: - losses = self.ground_losses.player_airlifts - else: - losses = self.ground_losses.enemy_airlifts - for loss in losses: - for unit_type in loss.cargo: - losses_by_type[unit_type] += 1 - return losses_by_type - - def ground_object_losses_by_type(self, player: bool) -> Dict[str, int]: - losses_by_type: Dict[str, int] = defaultdict(int) - if player: - losses = self.ground_losses.player_ground_objects - else: - losses = self.ground_losses.enemy_ground_objects - for loss in losses: - losses_by_type[loss.theater_unit.type.id] += 1 - return losses_by_type - - def scenery_losses_by_type(self, player: bool) -> Dict[str, int]: - losses_by_type: Dict[str, int] = defaultdict(int) - if player: - losses = self.ground_losses.player_scenery - else: - losses = self.ground_losses.enemy_scenery - for loss in losses: - losses_by_type[loss.trigger_zone.name] += 1 - return losses_by_type - - def dead_aircraft(self) -> AirLosses: - player_losses = [] - enemy_losses = [] - for unit_name in self.state_data.killed_aircraft: - aircraft = self.unit_map.flight(unit_name) - if aircraft is None: - logging.error(f"Could not find Flight matching {unit_name}") - continue - if aircraft.flight.departure.captured: - player_losses.append(aircraft) - else: - enemy_losses.append(aircraft) - - for unit_data in self.state_data.unit_hit_point_updates: - damaged_unit = FlyingUnitHitPointUpdate.from_json(unit_data, self.unit_map) - if damaged_unit is None: - continue - if damaged_unit.is_dead(): - # If unit already killed, nothing to do. - if unit_data["name"] in self.state_data.killed_aircraft: - continue - if damaged_unit.is_friendly(to_player=True): - player_losses.append(damaged_unit.unit) - else: - enemy_losses.append(damaged_unit.unit) - return AirLosses(player_losses, enemy_losses) - - def dead_ground_units(self) -> GroundLosses: - losses = GroundLosses() - for unit_name in self.state_data.killed_ground_units: - front_line_unit = self.unit_map.front_line_unit(unit_name) - if front_line_unit is not None: - if front_line_unit.origin.captured: - losses.player_front_line.append(front_line_unit) - else: - losses.enemy_front_line.append(front_line_unit) - continue - - convoy_unit = self.unit_map.convoy_unit(unit_name) - if convoy_unit is not None: - if convoy_unit.convoy.player_owned: - losses.player_convoy.append(convoy_unit) - else: - losses.enemy_convoy.append(convoy_unit) - continue - - cargo_ship = self.unit_map.cargo_ship(unit_name) - if cargo_ship is not None: - if cargo_ship.player_owned: - losses.player_cargo_ships.append(cargo_ship) - else: - losses.enemy_cargo_ships.append(cargo_ship) - continue - - ground_object = self.unit_map.theater_units(unit_name) - if ground_object is not None: - if ground_object.theater_unit.ground_object.is_friendly(to_player=True): - losses.player_ground_objects.append(ground_object) - else: - losses.enemy_ground_objects.append(ground_object) - continue - - scenery_object = self.unit_map.scenery_object(unit_name) - # Try appending object to the name, because we do this for building statics. - if scenery_object is not None: - if scenery_object.ground_unit.ground_object.is_friendly(to_player=True): - losses.player_scenery.append(scenery_object) - else: - losses.enemy_scenery.append(scenery_object) - continue - - airfield = self.unit_map.airfield(unit_name) - if airfield is not None: - if airfield.captured: - losses.player_airfields.append(airfield) - else: - losses.enemy_airfields.append(airfield) - continue - - # Only logging as debug because we don't currently track infantry - # deaths, so we expect to see quite a few unclaimed dead ground - # units. We should start tracking those and covert this to a - # warning. - logging.debug( - f"Death of untracked ground unit {unit_name} will " - "have no effect. This may be normal behavior." - ) - - for unit_name in self.state_data.killed_aircraft: - airlift_unit = self.unit_map.airlift_unit(unit_name) - if airlift_unit is not None: - if airlift_unit.transfer.player: - losses.player_airlifts.append(airlift_unit) - else: - losses.enemy_airlifts.append(airlift_unit) - continue - - for unit_data in self.state_data.unit_hit_point_updates: - damaged_unit = TheaterUnitHitPointUpdate.from_json(unit_data, self.unit_map) - if damaged_unit is None: - continue - if damaged_unit.is_dead(): - if unit_data["name"] in self.state_data.killed_ground_units: - continue - if damaged_unit.is_friendly(to_player=True): - losses.player_ground_objects.append(damaged_unit.unit) - else: - losses.enemy_ground_objects.append(damaged_unit.unit) - - return losses - - def unit_hit_point_update_events(self) -> List[TheaterUnitHitPointUpdate]: - damaged_units = [] - for unit_data in self.state_data.unit_hit_point_updates: - unit = TheaterUnitHitPointUpdate.from_json(unit_data, self.unit_map) - if unit is None: - continue - damaged_units.append(unit) - return damaged_units - - def base_capture_events(self) -> List[BaseCaptureEvent]: - """Keeps only the last instance of a base capture event for each base ID.""" - blue_coalition_id = 2 - seen = set() - captures = [] - for capture in reversed(self.state_data.base_capture_events): - # The ID string in the JSON file will be the UUID generated from liberation - cp_id, new_owner_id_str, _name = capture.split("||") - - # Only the most recent capture event matters. - if cp_id in seen: - continue - seen.add(cp_id) - - try: - control_point = self.game.theater.find_control_point_by_id(UUID(cp_id)) - except (KeyError, ValueError): - # Captured base is not a part of the campaign. This happens when neutral - # bases are near the conflict. Nothing to do. - continue - - captured_by_player = int(new_owner_id_str) == blue_coalition_id - if control_point.is_friendly(to_player=captured_by_player): - # Base is currently friendly to the new owner. Was captured and - # recaptured in the same mission. Nothing to do. - continue - - captures.append(BaseCaptureEvent(control_point, captured_by_player)) - return captures diff --git a/game/factions/__init__.py b/game/factions/__init__.py deleted file mode 100644 index 6b678491a..000000000 --- a/game/factions/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .faction import Faction diff --git a/game/factions/faction.py b/game/factions/faction.py deleted file mode 100644 index 6cb5f8ccf..000000000 --- a/game/factions/faction.py +++ /dev/null @@ -1,391 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -from dataclasses import dataclass, field -from functools import cached_property -from typing import Any, Dict, Iterator, List, Optional, TYPE_CHECKING, Type - -import dcs -from dcs.countries import country_dict -from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType - -from game.armedforces.forcegroup import ForceGroup -from game.data.building_data import ( - DEFAULT_AVAILABLE_BUILDINGS, - IADS_BUILDINGS, - REQUIRED_BUILDINGS, - WW2_ALLIES_BUILDINGS, - WW2_FREE, - WW2_GERMANY_BUILDINGS, -) -from game.data.doctrine import Doctrine -from game.data.groups import GroupRole -from game.data.units import UnitClass -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.dcs.shipunittype import ShipUnitType -from game.dcs.unittype import UnitType - -if TYPE_CHECKING: - from game.theater.start_generator import ModSettings - - -@dataclass -class Faction: - #: List of locales to use when generating random names. If not set, Faker will - #: choose the default locale. - locales: Optional[List[str]] - - # The unit type to spawn for cargo shipping. - cargo_ship: ShipUnitType - - # Country used by this faction - country: str = field(default="") - - # Nice name of the faction - name: str = field(default="") - - # List of faction file authors - authors: str = field(default="") - - # A description of the faction - description: str = field(default="") - - # Available aircraft - aircrafts: List[AircraftType] = field(default_factory=list) - - # Available awacs aircraft - awacs: List[AircraftType] = field(default_factory=list) - - # Available tanker aircraft - tankers: List[AircraftType] = field(default_factory=list) - - # Available frontline units - frontline_units: List[GroundUnitType] = field(default_factory=list) - - # Available artillery units - artillery_units: List[GroundUnitType] = field(default_factory=list) - - # Infantry units used - infantry_units: List[GroundUnitType] = field(default_factory=list) - - # Logistics units used - logistics_units: List[GroundUnitType] = field(default_factory=list) - - # Possible Air Defence units, Like EWRs - air_defense_units: List[GroundUnitType] = field(default_factory=list) - - # A list of all supported sets of units - preset_groups: list[ForceGroup] = field(default_factory=list) - - # Possible Missile site generators for this faction - missiles: List[GroundUnitType] = field(default_factory=list) - - # Required mods or asset packs - requirements: Dict[str, str] = field(default_factory=dict) - - # Possible carrier names - carrier_names: List[str] = field(default_factory=list) - - # Possible helicopter carrier names - helicopter_carrier_names: List[str] = field(default_factory=list) - - # Available Naval Units - naval_units: List[ShipUnitType] = field(default_factory=list) - - # Whether this faction has JTAC access - has_jtac: bool = field(default=False) - - # Unit to use as JTAC for this faction - jtac_unit: Optional[AircraftType] = field(default=None) - - # doctrine - doctrine: Doctrine = field(default=Doctrine.named("modern")) - - # List of available building layouts for this faction - building_set: List[str] = field(default_factory=list) - - # List of default livery overrides - liveries_overrides: Dict[AircraftType, List[str]] = field(default_factory=dict) - - #: Set to True if the faction should force the "Unrestricted satnav" option - #: for the mission. This option enables GPS for capable aircraft regardless - #: of the time period or operator. For example, the CJTF "countries" don't - #: appear to have GPS capability, so they need this. - #: - #: Note that this option cannot be set per-side. If either faction needs it, - #: both will use it. - unrestricted_satnav: bool = False - - def has_access_to_dcs_type(self, unit_type: Type[DcsUnitType]) -> bool: - # Vehicle and Ship Units - if any(unit_type == u.dcs_unit_type for u in self.accessible_units): - return True - - # Statics - if issubclass(unit_type, StaticType): - # TODO Improve the statics checking - # We currently do not have any list or similar to check if a faction has - # access to a specific static. There we accept any static here - return True - return False - - def has_access_to_unit_class(self, unit_class: UnitClass) -> bool: - return any(unit.unit_class is unit_class for unit in self.accessible_units) - - @cached_property - def accessible_units(self) -> list[UnitType[Any]]: - all_units: Iterator[UnitType[Any]] = itertools.chain( - self.ground_units, - self.infantry_units, - self.air_defense_units, - self.naval_units, - self.missiles, - ( - unit - for preset_group in self.preset_groups - for unit in preset_group.units - ), - ) - return list(set(all_units)) - - @property - def air_defenses(self) -> list[str]: - """Returns the Air Defense types""" - # This is used for the faction overview in NewGameWizard - air_defenses = [a.display_name for a in self.air_defense_units] - air_defenses.extend( - [ - pg.name - for pg in self.preset_groups - if any(task.role == GroupRole.AIR_DEFENSE for task in pg.tasks) - ] - ) - return sorted(air_defenses) - - @classmethod - def from_dict(cls: Type[Faction], json: Dict[str, Any]) -> Faction: - faction = Faction( - locales=json.get("locales"), - cargo_ship=ShipUnitType.named(json.get("cargo_ship", "Handy Wind")), - ) - - faction.country = json.get("country", "/") - if faction.country not in [c.name for c in country_dict.values()]: - raise AssertionError( - 'Faction\'s country ("{}") is not a valid DCS country ID'.format( - faction.country - ) - ) - - faction.name = json.get("name", "") - if not faction.name: - raise AssertionError("Faction has no valid name") - - faction.authors = json.get("authors", "") - faction.description = json.get("description", "") - - faction.aircrafts = [AircraftType.named(n) for n in json.get("aircrafts", [])] - faction.awacs = [AircraftType.named(n) for n in json.get("awacs", [])] - faction.tankers = [AircraftType.named(n) for n in json.get("tankers", [])] - - faction.aircrafts = list( - set(faction.aircrafts + faction.awacs + faction.tankers) - ) - - faction.frontline_units = [ - GroundUnitType.named(n) for n in json.get("frontline_units", []) - ] - faction.artillery_units = [ - GroundUnitType.named(n) for n in json.get("artillery_units", []) - ] - faction.infantry_units = [ - GroundUnitType.named(n) for n in json.get("infantry_units", []) - ] - faction.logistics_units = [ - GroundUnitType.named(n) for n in json.get("logistics_units", []) - ] - faction.air_defense_units = [ - GroundUnitType.named(n) for n in json.get("air_defense_units", []) - ] - faction.missiles = [GroundUnitType.named(n) for n in json.get("missiles", [])] - - faction.naval_units = [ - ShipUnitType.named(n) for n in json.get("naval_units", []) - ] - - faction.preset_groups = [ - ForceGroup.from_preset_group(g) for g in json.get("preset_groups", []) - ] - - faction.requirements = json.get("requirements", {}) - - faction.carrier_names = json.get("carrier_names", []) - faction.helicopter_carrier_names = json.get("helicopter_carrier_names", []) - - faction.has_jtac = json.get("has_jtac", False) - jtac_name = json.get("jtac_unit", None) - if jtac_name is not None: - faction.jtac_unit = AircraftType.named(jtac_name) - else: - faction.jtac_unit = None - - # Load doctrine - doctrine = json.get("doctrine", "modern") - faction.doctrine = Doctrine.named(doctrine) - - # Load the building set - faction.building_set = [] - building_set = json.get("building_set", "default") - if building_set == "default": - faction.building_set.extend(DEFAULT_AVAILABLE_BUILDINGS) - elif building_set == "ww2free": - faction.building_set.extend(WW2_FREE) - elif building_set == "ww2ally": - faction.building_set.extend(WW2_ALLIES_BUILDINGS) - elif building_set == "ww2germany": - faction.building_set.extend(WW2_GERMANY_BUILDINGS) - else: - faction.building_set.extend(DEFAULT_AVAILABLE_BUILDINGS) - - # Add required buildings for the game logic (e.g. ammo, factory..) - faction.building_set.extend(REQUIRED_BUILDINGS) - faction.building_set.extend(IADS_BUILDINGS) - - # Load liveries override - faction.liveries_overrides = {} - liveries_overrides = json.get("liveries_overrides", {}) - for name, livery in liveries_overrides.items(): - aircraft = AircraftType.named(name) - faction.liveries_overrides[aircraft] = [s.lower() for s in livery] - - faction.unrestricted_satnav = json.get("unrestricted_satnav", False) - - return faction - - @property - def ground_units(self) -> Iterator[GroundUnitType]: - yield from self.artillery_units - yield from self.frontline_units - yield from self.logistics_units - - def infantry_with_class(self, unit_class: UnitClass) -> Iterator[GroundUnitType]: - for unit in self.infantry_units: - if unit.unit_class is unit_class: - yield unit - - def apply_mod_settings(self, mod_settings: ModSettings) -> None: - # aircraft - if not mod_settings.a4_skyhawk: - self.remove_aircraft("A-4E-C") - if not mod_settings.hercules: - self.remove_aircraft("Hercules") - if not mod_settings.uh_60l: - self.remove_aircraft("UH-60L") - self.remove_aircraft("KC130J") - if not mod_settings.f22_raptor: - self.remove_aircraft("F-22A") - if not mod_settings.f104_starfighter: - self.remove_aircraft("VSN_F104G") - self.remove_aircraft("VSN_F104S") - self.remove_aircraft("VSN_F104S_AG") - if not mod_settings.f4_phantom: - self.remove_aircraft("VSN_F4B") - self.remove_aircraft("VSN_F4C") - if not mod_settings.jas39_gripen: - self.remove_aircraft("JAS39Gripen") - self.remove_aircraft("JAS39Gripen_AG") - if not mod_settings.su57_felon: - self.remove_aircraft("Su-57") - if not mod_settings.ov10a_bronco: - self.remove_aircraft("Bronco-OV-10A") - if not mod_settings.fa18efg: - self.remove_aircraft("FA_18E") - self.remove_aircraft("FA_18F") - self.remove_aircraft("EA_18G") - - # frenchpack - if not mod_settings.frenchpack: - self.remove_vehicle("AMX10RCR") - self.remove_vehicle("SEPAR") - self.remove_vehicle("ERC") - self.remove_vehicle("M120") - self.remove_vehicle("AA20") - self.remove_vehicle("TRM2000") - self.remove_vehicle("TRM2000_Citerne") - self.remove_vehicle("TRM2000_AA20") - self.remove_vehicle("TRMMISTRAL") - self.remove_vehicle("VABH") - self.remove_vehicle("VAB_RADIO") - self.remove_vehicle("VAB_50") - self.remove_vehicle("VIB_VBR") - self.remove_vehicle("VAB_HOT") - self.remove_vehicle("VAB_MORTIER") - self.remove_vehicle("VBL50") - self.remove_vehicle("VBLANF1") - self.remove_vehicle("VBL-radio") - self.remove_vehicle("VBAE") - self.remove_vehicle("VBAE_MMP") - self.remove_vehicle("AMX-30B2") - self.remove_vehicle("Tracma") - self.remove_vehicle("JTACFP") - self.remove_vehicle("SHERIDAN") - self.remove_vehicle("Leclerc_XXI") - self.remove_vehicle("Toyota_bleu") - self.remove_vehicle("Toyota_vert") - self.remove_vehicle("Toyota_desert") - self.remove_vehicle("Kamikaze") - self.remove_vehicle("AMX1375") - self.remove_vehicle("AMX1390") - self.remove_vehicle("VBCI") - self.remove_vehicle("T62") - self.remove_vehicle("T64BV") - self.remove_vehicle("T72M") - self.remove_vehicle("KORNET") - # high digit sams - if not mod_settings.high_digit_sams: - self.remove_preset("SA-10B/S-300PS") - self.remove_preset("SA-12/S-300V") - self.remove_preset("SA-20/S-300PMU-1") - self.remove_preset("SA-20B/S-300PMU-2") - self.remove_preset("SA-23/S-300VM") - self.remove_preset("SA-17") - self.remove_preset("KS-19") - self.remove_preset("HQ-2") - self.remove_preset("SA-2/S-75 V-759/5V23") - self.remove_preset("SA-3/S-125 V-601P/5V27") - self.remove_vehicle("SAM SA-14 Strela-3 manpad") - self.remove_vehicle("SAM SA-24 Igla-S manpad") - self.remove_vehicle("Polyana-D4M1 C2 node") - - def remove_aircraft(self, name: str) -> None: - for i in self.aircrafts: - if i.dcs_unit_type.id == name: - self.aircrafts.remove(i) - - def remove_preset(self, name: str) -> None: - for pg in self.preset_groups: - if pg.name == name: - self.preset_groups.remove(pg) - - def remove_vehicle(self, name: str) -> None: - for i in self.frontline_units: - if i.dcs_unit_type.id == name: - self.frontline_units.remove(i) - - -def load_ship(name: str) -> Optional[Type[ShipType]]: - if (ship := getattr(dcs.ships, name, None)) is not None: - return ship - logging.error(f"FACTION ERROR : Unable to find {name} in dcs.ships") - return None - - -def load_all_ships(data: list[str]) -> List[Type[ShipType]]: - items = [] - for name in data: - item = load_ship(name) - if item is not None: - items.append(item) - return items diff --git a/game/factions/factions.py b/game/factions/factions.py deleted file mode 100644 index 37f8e8361..000000000 --- a/game/factions/factions.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import annotations - -import itertools -import json -import logging -from collections.abc import Iterator -from pathlib import Path - -import yaml - -from game import persistence -from .faction import Faction - - -class Factions: - def __init__(self, factions: dict[str, Faction]) -> None: - self.factions = factions - self.campaign_defined_factions: dict[str, Faction] = {} - - def get_by_name(self, name: str) -> Faction: - try: - return self.factions[name] - except KeyError: - return self.campaign_defined_factions[name] - - def iter_faction_names(self) -> Iterator[str]: - # Campaign defined factions first so they show up at the top of the list in the - # UI. - return itertools.chain(self.campaign_defined_factions, self.factions) - - def add_campaign_defined(self, faction: Faction) -> None: - if ( - faction.name in self.factions - or faction.name in self.campaign_defined_factions - ): - raise KeyError(f"Duplicate faction {faction.name}") - self.campaign_defined_factions[faction.name] = faction - - def reset_campaign_defined(self) -> None: - self.campaign_defined_factions = {} - - @staticmethod - def iter_faction_files_in(path: Path) -> Iterator[Path]: - yield from path.glob("*.json") - yield from path.glob("*.yaml") - - @classmethod - def iter_faction_files(cls) -> Iterator[Path]: - yield from cls.iter_faction_files_in(Path("resources/factions/")) - yield from cls.iter_faction_files_in( - Path(persistence.base_path()) / "Liberation/Factions" - ) - - @classmethod - def load(cls) -> Factions: - factions = {} - for path in cls.iter_faction_files(): - try: - with path.open("r", encoding="utf-8") as fdata: - if path.suffix == ".yaml": - data = yaml.safe_load(fdata) - else: - data = json.load(fdata) - faction = Faction.from_dict(data) - factions[faction.name] = faction - logging.info("Loaded faction from %s", path) - except Exception: - logging.exception(f"Unable to load faction from %s", path) - - return Factions(factions) diff --git a/game/flightplan/__init__.py b/game/flightplan/__init__.py deleted file mode 100644 index 4e57dff56..000000000 --- a/game/flightplan/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .holdzonegeometry import HoldZoneGeometry -from .joinzonegeometry import JoinZoneGeometry diff --git a/game/flightplan/holdzonegeometry.py b/game/flightplan/holdzonegeometry.py deleted file mode 100644 index a5c371493..000000000 --- a/game/flightplan/holdzonegeometry.py +++ /dev/null @@ -1,109 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import shapely.ops -from dcs import Point -from shapely.geometry import MultiPolygon, Point as ShapelyPoint, Polygon - -from game.utils import nautical_miles - -if TYPE_CHECKING: - from game.coalition import Coalition - from game.theater import ConflictTheater - - -class HoldZoneGeometry: - """Defines the zones used for finding optimal hold point placement. - - The zones themselves are stored in the class rather than just the resulting hold - point so that the zones can be drawn in the map for debugging purposes. - """ - - def __init__( - self, - target: Point, - home: Point, - ip: Point, - join: Point, - coalition: Coalition, - theater: ConflictTheater, - ) -> None: - self._target = target - # Hold points are placed one of two ways. Either approach guarantees: - # - # * Safe hold point. - # * Minimum distance to the join point. - # * Not closer to the target than the join point. - # - # 1. As near the join point as possible with a specific distance from the - # departure airfield. This prevents loitering directly above the airfield but - # also keeps the hold point close to the departure airfield. - # - # 2. Alternatively, if the entire home zone is excluded by the above criteria, - # as neat the departure airfield as possible within a minimum distance from - # the join point, with a restricted turn angle at the join point. This - # handles the case where we need to backtrack from the departure airfield and - # the join point to place the hold point, but the turn angle limit restricts - # the maximum distance of the backtrack while maintaining the direction of - # the flight plan. - self.threat_zone = coalition.opponent.threat_zone.all - self.home = ShapelyPoint(home.x, home.y) - - self.join = ShapelyPoint(join.x, join.y) - - self.join_bubble = self.join.buffer(coalition.doctrine.push_distance.meters) - - join_to_target_distance = join.distance_to_point(target) - self.target_bubble = ShapelyPoint(target.x, target.y).buffer( - join_to_target_distance - ) - - self.home_bubble = self.home.buffer(coalition.doctrine.hold_distance.meters) - - excluded_zones = shapely.ops.unary_union( - [self.join_bubble, self.target_bubble, self.threat_zone] - ) - if not isinstance(excluded_zones, MultiPolygon): - excluded_zones = MultiPolygon([excluded_zones]) - self.excluded_zones = excluded_zones - - join_heading = ip.heading_between_point(join) - - # Arbitrarily large since this is later constrained by the map boundary, and - # we'll be picking a location close to the IP anyway. Just used to avoid real - # distance calculations to project to the map edge. - large_distance = nautical_miles(400).meters - turn_limit = 40 - join_limit_ccw = join.point_from_heading( - join_heading - turn_limit, large_distance - ) - join_limit_cw = join.point_from_heading( - join_heading + turn_limit, large_distance - ) - - join_direction_limit_wedge = Polygon( - [ - (join.x, join.y), - (join_limit_ccw.x, join_limit_ccw.y), - (join_limit_cw.x, join_limit_cw.y), - ] - ) - - permissible_zones = ( - coalition.nav_mesh.map_bounds(theater) - .intersection(join_direction_limit_wedge) - .difference(self.excluded_zones) - .difference(self.home_bubble) - ) - if not isinstance(permissible_zones, MultiPolygon): - permissible_zones = MultiPolygon([permissible_zones]) - self.permissible_zones = permissible_zones - self.preferred_lines = self.home_bubble.boundary.difference(self.excluded_zones) - - def find_best_hold_point(self) -> Point: - if self.preferred_lines.is_empty: - hold, _ = shapely.ops.nearest_points(self.permissible_zones, self.home) - else: - hold, _ = shapely.ops.nearest_points(self.preferred_lines, self.join) - return self._target.new_in_same_map(hold.x, hold.y) diff --git a/game/flightplan/ipsolver.py b/game/flightplan/ipsolver.py deleted file mode 100644 index e4cb943d4..000000000 --- a/game/flightplan/ipsolver.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from typing import Any - -from shapely.geometry import MultiPolygon, Point -from shapely.geometry.base import BaseGeometry - -from game.data.doctrine import Doctrine -from game.flightplan.waypointsolver import WaypointSolver -from game.flightplan.waypointstrategy import WaypointStrategy -from game.utils import meters, nautical_miles - -MIN_DISTANCE_FROM_DEPARTURE = nautical_miles(5) - - -class ThreatTolerantIpStrategy(WaypointStrategy): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__(threat_zones) - self.prerequisite(target).min_distance_from( - departure, doctrine.min_ingress_distance - ) - self.require().at_least(MIN_DISTANCE_FROM_DEPARTURE).away_from(departure) - self.require().at_most(meters(departure.distance(target))).away_from(departure) - self.require().at_least(doctrine.min_ingress_distance).away_from(target) - max_ip_range = min( - doctrine.max_ingress_distance, meters(departure.distance(target)) - ) - self.require().at_most(max_ip_range).away_from(target) - self.threat_tolerance(target, max_ip_range, nautical_miles(5)) - self.nearest(departure) - - -class UnsafeIpStrategy(WaypointStrategy): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__(threat_zones) - self.prerequisite(target).min_distance_from( - departure, doctrine.min_ingress_distance - ) - self.require().at_least(MIN_DISTANCE_FROM_DEPARTURE).away_from( - departure, "departure" - ) - self.require().at_most(meters(departure.distance(target))).away_from( - departure, "departure" - ) - self.require().at_least(doctrine.min_ingress_distance).away_from( - target, "target" - ) - max_ip_range = min( - doctrine.max_ingress_distance, meters(departure.distance(target)) - ) - self.require().at_most(max_ip_range).away_from(target, "target") - self.nearest(departure) - - -class SafeIpStrategy(WaypointStrategy): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__(threat_zones) - self.prerequisite(departure).is_safe() - self.prerequisite(target).min_distance_from( - departure, doctrine.min_ingress_distance - ) - self.require().at_least(MIN_DISTANCE_FROM_DEPARTURE).away_from( - departure, "departure" - ) - self.require().at_most(meters(departure.distance(target))).away_from( - departure, "departure" - ) - self.require().at_least(doctrine.min_ingress_distance).away_from( - target, "target" - ) - self.require().at_most( - min(doctrine.max_ingress_distance, meters(departure.distance(target))) - ).away_from(target, "target") - self.require().safe() - self.nearest(departure) - - -class SafeBackTrackingIpStrategy(WaypointStrategy): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__(threat_zones) - self.require().at_least(MIN_DISTANCE_FROM_DEPARTURE).away_from( - departure, "departure" - ) - self.require().at_least(doctrine.min_ingress_distance).away_from( - target, "target" - ) - self.require().at_most(doctrine.max_ingress_distance).away_from( - target, "target" - ) - self.require().safe() - self.nearest(departure) - - -class UnsafeBackTrackingIpStrategy(WaypointStrategy): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__(threat_zones) - self.require().at_least(MIN_DISTANCE_FROM_DEPARTURE).away_from( - departure, "departure" - ) - self.require().at_least(doctrine.min_ingress_distance).away_from( - target, "target" - ) - self.require().at_most(doctrine.max_ingress_distance).away_from( - target, "target" - ) - self.nearest(departure) - - -class IpSolver(WaypointSolver): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - super().__init__() - self.departure = departure - self.target = target - self.doctrine = doctrine - self.threat_zones = threat_zones - - self.add_strategy(SafeIpStrategy(departure, target, doctrine, threat_zones)) - self.add_strategy( - ThreatTolerantIpStrategy(departure, target, doctrine, threat_zones) - ) - self.add_strategy(UnsafeIpStrategy(departure, target, doctrine, threat_zones)) - self.add_strategy( - SafeBackTrackingIpStrategy(departure, target, doctrine, threat_zones) - ) - # TODO: The cases that require this are not covered by any tests. - self.add_strategy( - UnsafeBackTrackingIpStrategy(departure, target, doctrine, threat_zones) - ) - - def describe_metadata(self) -> dict[str, Any]: - return {"doctrine": self.doctrine.name} - - def describe_inputs(self) -> Iterator[tuple[str, BaseGeometry]]: - yield "departure", self.departure - yield "target", self.target - yield "threat_zones", self.threat_zones diff --git a/game/flightplan/joinzonegeometry.py b/game/flightplan/joinzonegeometry.py deleted file mode 100644 index 75548e274..000000000 --- a/game/flightplan/joinzonegeometry.py +++ /dev/null @@ -1,106 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import shapely.ops -from dcs import Point -from shapely.geometry import ( - MultiLineString, - MultiPolygon, - Point as ShapelyPoint, - Polygon, -) - -from game.utils import nautical_miles - -if TYPE_CHECKING: - from game.coalition import Coalition - - -class JoinZoneGeometry: - """Defines the zones used for finding optimal join point placement. - - The zones themselves are stored in the class rather than just the resulting join - point so that the zones can be drawn in the map for debugging purposes. - """ - - def __init__( - self, target: Point, home: Point, ip: Point, coalition: Coalition - ) -> None: - self._target = target - # Normal join placement is based on the path from home to the IP. If no path is - # found it means that the target is on a direct path. In that case we instead - # want to enforce that the join point is: - # - # * Not closer to the target than the IP. - # * Not too close to the home airfield. - # * Not threatened. - # * A minimum distance from the IP. - # * Not too sharp a turn at the ingress point. - self.ip = ShapelyPoint(ip.x, ip.y) - self.threat_zone = coalition.opponent.threat_zone.all - self.home = ShapelyPoint(home.x, home.y) - - self.ip_bubble = self.ip.buffer(coalition.doctrine.join_distance.meters) - - ip_distance = ip.distance_to_point(target) - self.target_bubble = ShapelyPoint(target.x, target.y).buffer(ip_distance) - - # The minimum distance between the home location and the IP. - min_distance_from_home = nautical_miles(5) - - self.home_bubble = self.home.buffer(min_distance_from_home.meters) - - excluded_zones = shapely.ops.unary_union( - [self.ip_bubble, self.target_bubble, self.threat_zone] - ) - - if not isinstance(excluded_zones, MultiPolygon): - excluded_zones = MultiPolygon([excluded_zones]) - self.excluded_zones = excluded_zones - - ip_heading = target.heading_between_point(ip) - - # Arbitrarily large since this is later constrained by the map boundary, and - # we'll be picking a location close to the IP anyway. Just used to avoid real - # distance calculations to project to the map edge. - large_distance = nautical_miles(400).meters - turn_limit = 40 - ip_limit_ccw = ip.point_from_heading(ip_heading - turn_limit, large_distance) - ip_limit_cw = ip.point_from_heading(ip_heading + turn_limit, large_distance) - - ip_direction_limit_wedge = Polygon( - [ - (ip.x, ip.y), - (ip_limit_ccw.x, ip_limit_ccw.y), - (ip_limit_cw.x, ip_limit_cw.y), - ] - ) - - permissible_zones = ip_direction_limit_wedge.difference( - self.excluded_zones - ).difference(self.home_bubble) - if permissible_zones.is_empty: - permissible_zones = MultiPolygon([]) - if not isinstance(permissible_zones, MultiPolygon): - permissible_zones = MultiPolygon([permissible_zones]) - self.permissible_zones = permissible_zones - - preferred_lines = ip_direction_limit_wedge.intersection( - self.excluded_zones.boundary - ).difference(self.home_bubble) - - if preferred_lines.is_empty: - preferred_lines = MultiLineString([]) - if not isinstance(preferred_lines, MultiLineString): - preferred_lines = MultiLineString([preferred_lines]) - self.preferred_lines = preferred_lines - - def find_best_join_point(self) -> Point: - # TODO: afaict the permissible_lines case is entirely unnecessary. The two - # definitions appear equivalent. - if self.preferred_lines.is_empty: - join, _ = shapely.ops.nearest_points(self.permissible_zones, self.ip) - else: - join, _ = shapely.ops.nearest_points(self.preferred_lines, self.ip) - return self._target.new_in_same_map(join.x, join.y) diff --git a/game/flightplan/refuelzonegeometry.py b/game/flightplan/refuelzonegeometry.py deleted file mode 100644 index 0c556a6d1..000000000 --- a/game/flightplan/refuelzonegeometry.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from dcs import Point - -if TYPE_CHECKING: - from game.coalition import Coalition - - -class RefuelZoneGeometry: - def __init__( - self, - package_home: Point, - join: Point, - coalition: Coalition, - ) -> None: - self.package_home = package_home - self.join = join - self.coalition = coalition - - def find_best_refuel_point(self) -> Point: - # Do simple at first. - # TODO: Avoid threatened areas, minimize backtracking. - # https://github.com/dcs-liberation/dcs_liberation/issues/2542 - distance = 0.75 * self.package_home.distance_to_point(self.join) - heading = self.package_home.heading_between_point(self.join) - return self.package_home.point_from_heading(heading, distance) diff --git a/game/flightplan/waypointactions/__init__.py b/game/flightplan/waypointactions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/flightplan/waypointactions/engagetargets.py b/game/flightplan/waypointactions/engagetargets.py deleted file mode 100644 index 0df7bb0a6..000000000 --- a/game/flightplan/waypointactions/engagetargets.py +++ /dev/null @@ -1,35 +0,0 @@ -from collections.abc import Iterator -from datetime import datetime, timedelta - -import dcs.task -from dcs.task import Task - -from game.ato.flightstate.actionstate import ActionState -from game.utils import Distance -from .taskcontext import TaskContext -from .waypointaction import WaypointAction - - -class EngageTargets(WaypointAction): - def __init__( - self, - max_distance_from_flight: Distance, - target_types: list[type[dcs.task.TargetType]], - ) -> None: - self._max_distance_from_flight = max_distance_from_flight - self._target_types = target_types - - def update_state( - self, state: ActionState, time: datetime, duration: timedelta - ) -> timedelta: - state.finish() - return duration - - def describe(self) -> str: - return "Searching for targets" - - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - yield dcs.task.EngageTargets( - max_distance=int(self._max_distance_from_flight.meters), - targets=self._target_types, - ) diff --git a/game/flightplan/waypointactions/hold.py b/game/flightplan/waypointactions/hold.py deleted file mode 100644 index 71da92271..000000000 --- a/game/flightplan/waypointactions/hold.py +++ /dev/null @@ -1,57 +0,0 @@ -from collections.abc import Iterator -from datetime import datetime, timedelta - -from dcs.task import Task, OrbitAction, ControlledTask - -from game.ato.flightstate.actionstate import ActionState -from game.provider import Provider -from game.utils import Distance, Speed -from .taskcontext import TaskContext -from .waypointaction import WaypointAction - - -class Hold(WaypointAction): - """Loiter at a location until a push time to synchronize with other flights. - - Taxi behavior is extremely unpredictable, so we cannot reliably predict ETAs for - waypoints without first fixing a time for one waypoint by holding until a sync time. - This is typically done with a dedicated hold point. If the flight reaches the hold - point before their push time, they will loiter at that location rather than fly to - their next waypoint as a speed that's often dangerously slow. - """ - - def __init__( - self, push_time_provider: Provider[datetime], altitude: Distance, speed: Speed - ) -> None: - self._push_time_provider = push_time_provider - self._altitude = altitude - self._speed = speed - - def describe(self) -> str: - return self._push_time_provider().strftime("Holding until %H:%M:%S") - - def update_state( - self, state: ActionState, time: datetime, duration: timedelta - ) -> timedelta: - push_time = self._push_time_provider() - if push_time <= time: - state.finish() - return time - push_time - return timedelta() - - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - remaining_time = self._push_time_provider() - ctx.mission_start_time - if remaining_time <= timedelta(): - return - - loiter = ControlledTask( - OrbitAction( - altitude=int(self._altitude.meters), - pattern=OrbitAction.OrbitPattern.Circle, - speed=self._speed.kph, - ) - ) - # The DCS task is serialized using the time from mission start, not the actual - # time. - loiter.stop_after_time(int(remaining_time.total_seconds())) - yield loiter diff --git a/game/flightplan/waypointactions/taskcontext.py b/game/flightplan/waypointactions/taskcontext.py deleted file mode 100644 index 8a3a3884c..000000000 --- a/game/flightplan/waypointactions/taskcontext.py +++ /dev/null @@ -1,7 +0,0 @@ -from dataclasses import dataclass -from datetime import datetime - - -@dataclass(frozen=True) -class TaskContext: - mission_start_time: datetime diff --git a/game/flightplan/waypointactions/waypointaction.py b/game/flightplan/waypointactions/waypointaction.py deleted file mode 100644 index a82a86789..000000000 --- a/game/flightplan/waypointactions/waypointaction.py +++ /dev/null @@ -1,29 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from dcs.task import Task - -from .taskcontext import TaskContext - -if TYPE_CHECKING: - from game.ato.flightstate.actionstate import ActionState - - -class WaypointAction(ABC): - @abstractmethod - def describe(self) -> str: - ... - - @abstractmethod - def update_state( - self, state: ActionState, time: datetime, duration: timedelta - ) -> timedelta: - ... - - @abstractmethod - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - ... diff --git a/game/flightplan/waypointoptions/__init__.py b/game/flightplan/waypointoptions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/flightplan/waypointoptions/formation.py b/game/flightplan/waypointoptions/formation.py deleted file mode 100644 index dcf48297d..000000000 --- a/game/flightplan/waypointoptions/formation.py +++ /dev/null @@ -1,21 +0,0 @@ -from collections.abc import Iterator -from enum import Enum - -from dcs.task import OptFormation, Task - -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.flightplan.waypointoptions.waypointoption import WaypointOption - - -class Formation(WaypointOption, Enum): - FINGER_FOUR_CLOSE = OptFormation.finger_four_close() - FINGER_FOUR_OPEN = OptFormation.finger_four_open() - LINE_ABREAST_OPEN = OptFormation.line_abreast_open() - SPREAD_FOUR_OPEN = OptFormation.spread_four_open() - TRAIL_OPEN = OptFormation.trail_open() - - def id(self) -> str: - return "formation" - - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - yield self.value diff --git a/game/flightplan/waypointoptions/waypointoption.py b/game/flightplan/waypointoptions/waypointoption.py deleted file mode 100644 index 6cdf945f3..000000000 --- a/game/flightplan/waypointoptions/waypointoption.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator - -from dcs.task import Task - -from game.flightplan.waypointactions.taskcontext import TaskContext - - -# Not explicitly an ABC because that prevents subclasses from deriving Enum. -class WaypointOption: - def id(self) -> str: - raise RuntimeError - - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - raise RuntimeError diff --git a/game/flightplan/waypointsolver.py b/game/flightplan/waypointsolver.py deleted file mode 100644 index 6a2a029dd..000000000 --- a/game/flightplan/waypointsolver.py +++ /dev/null @@ -1,140 +0,0 @@ -from __future__ import annotations - -import json -from collections.abc import Iterator -from pathlib import Path -from typing import TYPE_CHECKING, Any - -from dcs import Point -from dcs.mapping import Point as DcsPoint -from dcs.terrain import Terrain -from numpy import float64, array -from numpy._typing import NDArray -from shapely import transform, to_geojson -from shapely.geometry.base import BaseGeometry - -if TYPE_CHECKING: - from .waypointstrategy import WaypointStrategy - - -class NoSolutionsError(RuntimeError): - pass - - -class WaypointSolver: - def __init__(self) -> None: - self.strategies: list[WaypointStrategy] = [] - self.debug_output_directory: Path | None = None - self._terrain: Terrain | None = None - - def add_strategy(self, strategy: WaypointStrategy) -> None: - self.strategies.append(strategy) - - def set_debug_properties(self, path: Path, terrain: Terrain) -> None: - self.debug_output_directory = path - self._terrain = terrain - - def to_geojson(self, geometry: BaseGeometry) -> dict[str, Any]: - if geometry.is_empty: - return json.loads(to_geojson(geometry)) - - assert self._terrain is not None - origin = DcsPoint(0, 0, self._terrain) - - def xy_to_ll(points: NDArray[float64]) -> NDArray[float64]: - ll_points = [] - for point in points: - p = origin.new_in_same_map(point[0], point[1]) - latlng = p.latlng() - # Longitude is unintuitively first because it's the "X" coordinate: - # https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.1 - ll_points.append([latlng.lng, latlng.lat]) - return array(ll_points) - - transformed = transform(geometry, xy_to_ll) - return json.loads(to_geojson(transformed)) - - def describe_metadata(self) -> dict[str, Any]: - return {} - - def describe_inputs(self) -> Iterator[tuple[str, BaseGeometry]]: - yield from [] - - def describe_debug(self) -> dict[str, Any]: - assert self._terrain is not None - metadata = {"name": self.__class__.__name__, "terrain": self._terrain.name} - metadata.update(self.describe_metadata()) - return { - "type": "FeatureCollection", - # The GeoJSON spec forbids us from adding a "properties" field to a feature - # collection, but it doesn't restrict us from adding our own custom fields. - # https://gis.stackexchange.com/a/209263 - # - # It's possible that some consumers won't work with this, but we don't read - # collections directly with shapely and geojson.io is happy with it, so it - # works where we need it to. - "metadata": metadata, - "features": list(self.describe_features()), - } - - def describe_features(self) -> Iterator[dict[str, Any]]: - for description, geometry in self.describe_inputs(): - yield { - "type": "Feature", - "properties": { - "description": description, - }, - "geometry": self.to_geojson(geometry), - } - - def dump_debug_info(self) -> None: - path = self.debug_output_directory - if path is None: - return - - path.mkdir(exist_ok=True, parents=True) - - inputs_path = path / "solver.json" - with inputs_path.open("w", encoding="utf-8") as inputs_file: - json.dump(self.describe_debug(), inputs_file) - - features = list(self.describe_features()) - for idx, strategy in enumerate(self.strategies): - strategy_path = path / f"{idx}.json" - with strategy_path.open("w", encoding="utf-8") as strategy_debug_file: - json.dump( - { - "type": "FeatureCollection", - "metadata": { - "name": strategy.__class__.__name__, - "prerequisites": [ - p.describe_debug_info(self.to_geojson) - for p in strategy.prerequisites - ], - }, - # Include the solver's features in the strategy feature - # collection for easy copy/paste into geojson.io. - "features": features - + [ - d.to_geojson(self.to_geojson) - for d in strategy.iter_debug_info() - ], - }, - strategy_debug_file, - ) - - def solve(self) -> Point: - if not self.strategies: - raise ValueError( - "WaypointSolver.solve() called before any strategies were added" - ) - - for strategy in self.strategies: - if (point := strategy.find()) is not None: - return point - - self.dump_debug_info() - debug_details = "No debug output directory set" - if (debug_path := self.debug_output_directory) is not None: - debug_details = f"Debug details written to {debug_path}" - raise NoSolutionsError(f"No solutions found for waypoint. {debug_details}") diff --git a/game/flightplan/waypointsolverloader.py b/game/flightplan/waypointsolverloader.py deleted file mode 100644 index 530724f71..000000000 --- a/game/flightplan/waypointsolverloader.py +++ /dev/null @@ -1,76 +0,0 @@ -import json -from functools import cached_property -from pathlib import Path -from typing import Any - -from dcs.mapping import Point as DcsPoint, LatLng -from dcs.terrain import Terrain -from numpy import float64, array -from numpy._typing import NDArray -from shapely import transform -from shapely.geometry import shape -from shapely.geometry.base import BaseGeometry - -from game.data.doctrine import Doctrine -from .ipsolver import IpSolver -from .waypointsolver import WaypointSolver -from ..theater.theaterloader import TERRAINS_BY_NAME - - -def doctrine_from_name(name: str) -> Doctrine: - return Doctrine.named(name) - - -def geometry_ll_to_xy(geometry: BaseGeometry, terrain: Terrain) -> BaseGeometry: - if geometry.is_empty: - return geometry - - def ll_to_xy(points: NDArray[float64]) -> NDArray[float64]: - ll_points = [] - for point in points: - # Longitude is unintuitively first because it's the "X" coordinate: - # https://datatracker.ietf.org/doc/html/rfc7946#section-3.1.1 - p = DcsPoint.from_latlng(LatLng(point[1], point[0]), terrain) - ll_points.append([p.x, p.y]) - return array(ll_points) - - return transform(geometry, ll_to_xy) - - -class WaypointSolverLoader: - def __init__(self, debug_info_path: Path) -> None: - self.debug_info_path = debug_info_path - - def load_data(self) -> dict[str, Any]: - with self.debug_info_path.open(encoding="utf-8") as debug_info_file: - return json.load(debug_info_file) - - @staticmethod - def load_geometries( - feature_collection: dict[str, Any], terrain: Terrain - ) -> dict[str, BaseGeometry]: - geometries = {} - for feature in feature_collection["features"]: - description = feature["properties"]["description"] - geometry = shape(feature["geometry"]) - geometries[description] = geometry_ll_to_xy(geometry, terrain) - return geometries - - @cached_property - def terrain(self) -> Terrain: - return TERRAINS_BY_NAME[self.load_data()["metadata"]["terrain"]] - - def load(self) -> WaypointSolver: - data = self.load_data() - metadata = data["metadata"] - name = metadata.pop("name") - terrain_name = metadata.pop("terrain") - terrain = TERRAINS_BY_NAME[terrain_name] - if "doctrine" in metadata: - metadata["doctrine"] = doctrine_from_name(metadata["doctrine"]) - geometries = self.load_geometries(data, terrain) - builder: type[WaypointSolver] = { - "IpSolver": IpSolver, - }[name] - metadata.update(geometries) - return builder(**metadata) diff --git a/game/flightplan/waypointstrategy.py b/game/flightplan/waypointstrategy.py deleted file mode 100644 index d91bf3f61..000000000 --- a/game/flightplan/waypointstrategy.py +++ /dev/null @@ -1,268 +0,0 @@ -from __future__ import annotations - -import math -from abc import abstractmethod, ABC -from collections.abc import Iterator, Callable -from dataclasses import dataclass -from typing import Any - -from dcs.mapping import heading_between_points -from shapely.geometry import Point, MultiPolygon, Polygon -from shapely.geometry.base import BaseGeometry as Geometry, BaseGeometry -from shapely.ops import nearest_points - -from game.utils import Distance, nautical_miles, Heading - - -def angle_between_points(a: Point, b: Point) -> float: - return heading_between_points(a.x, a.y, b.x, b.y) - - -def point_at_heading(p: Point, heading: Heading, distance: Distance) -> Point: - rad_heading = heading.radians - return Point( - p.x + math.cos(rad_heading) * distance.meters, - p.y + math.sin(rad_heading) * distance.meters, - ) - - -class Prerequisite(ABC): - @abstractmethod - def is_satisfied(self) -> bool: - ... - - @abstractmethod - def describe_debug_info( - self, to_geojson: Callable[[BaseGeometry], dict[str, Any]] - ) -> dict[str, Any]: - ... - - -class DistancePrerequisite(Prerequisite): - def __init__(self, a: Point, b: Point, min_range: Distance) -> None: - self.a = a - self.b = b - self.min_range = min_range - - def is_satisfied(self) -> bool: - return self.a.distance(self.b) >= self.min_range.meters - - def describe_debug_info( - self, to_geojson: Callable[[BaseGeometry], dict[str, Any]] - ) -> dict[str, Any]: - return { - "requirement": f"at least {self.min_range} between", - "satisfied": self.is_satisfied(), - "subject": to_geojson(self.a), - "target": to_geojson(self.b), - } - - -class SafePrerequisite(Prerequisite): - def __init__(self, point: Point, threat_zones: MultiPolygon) -> None: - self.point = point - self.threat_zones = threat_zones - - def is_satisfied(self) -> bool: - return not self.point.intersects(self.threat_zones) - - def describe_debug_info( - self, to_geojson: Callable[[BaseGeometry], dict[str, Any]] - ) -> dict[str, Any]: - return { - "requirement": "is safe", - "satisfied": self.is_satisfied(), - "subject": to_geojson(self.point), - } - - -class PrerequisiteBuilder: - def __init__( - self, subject: Point, threat_zones: MultiPolygon, strategy: WaypointStrategy - ) -> None: - self.subject = subject - self.threat_zones = threat_zones - self.strategy = strategy - - def is_safe(self) -> None: - self.strategy.add_prerequisite( - SafePrerequisite(self.subject, self.threat_zones) - ) - - def min_distance_from(self, target: Point, distance: Distance) -> None: - self.strategy.add_prerequisite( - DistancePrerequisite(self.subject, target, distance) - ) - - -@dataclass(frozen=True) -class ThreatTolerance: - target: Point - target_buffer: Distance - tolerance: Distance - - -class RequirementBuilder: - def __init__(self, threat_zones: MultiPolygon, strategy: WaypointStrategy) -> None: - self.threat_zones = threat_zones - self.strategy = strategy - - def safe(self) -> None: - self.strategy.exclude_threat_zone() - - def at_least(self, distance: Distance) -> DistanceRequirementBuilder: - return DistanceRequirementBuilder(self.strategy, min_distance=distance) - - def at_most(self, distance: Distance) -> DistanceRequirementBuilder: - return DistanceRequirementBuilder(self.strategy, max_distance=distance) - - def maximum_turn_to( - self, turn_point: Point, next_point: Point, turn_limit: Heading - ) -> None: - large_distance = nautical_miles(400) - next_heading = Heading.from_degrees( - angle_between_points(next_point, turn_point) - ) - limit_ccw = point_at_heading( - turn_point, next_heading - turn_limit, large_distance - ) - limit_cw = point_at_heading( - turn_point, next_heading + turn_limit, large_distance - ) - - allowed_wedge = Polygon([turn_point, limit_ccw, limit_cw]) - self.strategy.exclude( - f"restrict turn from {turn_point} to {next_point} to {turn_limit}", - turn_point.buffer(large_distance.meters).difference(allowed_wedge), - ) - - -class DistanceRequirementBuilder: - def __init__( - self, - strategy: WaypointStrategy, - min_distance: Distance | None = None, - max_distance: Distance | None = None, - ) -> None: - if min_distance is None and max_distance is None: - raise ValueError - self.strategy = strategy - self.min_distance = min_distance - self.max_distance = max_distance - - def away_from(self, target: Point, description: str | None = None) -> None: - if description is None: - description = str(target) - - if self.min_distance is not None: - self.strategy.exclude( - f"at least {self.min_distance} away from {description}", - target.buffer(self.min_distance.meters), - ) - if self.max_distance is not None: - self.strategy.exclude_beyond( - f"at most {self.max_distance} away from {description}", - target.buffer(self.max_distance.meters), - ) - - -@dataclass(frozen=True) -class WaypointDebugInfo: - description: str - geometry: BaseGeometry - - def to_geojson( - self, to_geojson: Callable[[BaseGeometry], dict[str, Any]] - ) -> dict[str, Any]: - return { - "type": "Feature", - "properties": { - "description": self.description, - }, - "geometry": to_geojson(self.geometry), - } - - -class WaypointStrategy: - def __init__(self, threat_zones: MultiPolygon) -> None: - self.threat_zones = threat_zones - self.prerequisites: list[Prerequisite] = [] - self._max_area = Point(0, 0).buffer(2_000_000) - self.allowed_area = self._max_area.buffer(0) - self.debug_infos: list[WaypointDebugInfo] = [] - self._threat_tolerance: ThreatTolerance | None = None - self.point_for_nearest_solution: Point | None = None - - def add_prerequisite(self, prerequisite: Prerequisite) -> None: - self.prerequisites.append(prerequisite) - - def prerequisite(self, subject: Point) -> PrerequisiteBuilder: - return PrerequisiteBuilder(subject, self.threat_zones, self) - - def exclude(self, description: str, geometry: Geometry) -> None: - self.debug_infos.append(WaypointDebugInfo(description, geometry)) - self.allowed_area = self.allowed_area.difference(geometry) - - def exclude_beyond(self, description: str, geometry: Geometry) -> None: - self.exclude(description, self._max_area.difference(geometry)) - - def exclude_threat_zone(self) -> None: - if (tolerance := self._threat_tolerance) is not None: - description = ( - f"safe with a {tolerance.tolerance} tolerance to a " - f"{tolerance.target_buffer} radius about {tolerance.target}" - ) - else: - description = "safe" - self.exclude(description, self.threat_zones) - - def prerequisites_are_satisfied(self) -> bool: - for prereq in self.prerequisites: - if not prereq.is_satisfied(): - return False - return True - - def require(self) -> RequirementBuilder: - return RequirementBuilder(self.threat_zones, self) - - def threat_tolerance( - self, target: Point, target_size: Distance, wiggle: Distance - ) -> None: - if self.threat_zones.is_empty: - return - - min_distance_from_threat_to_target_buffer = target.buffer( - target_size.meters - ).distance(self.threat_zones.boundary) - threat_mask = self.threat_zones.buffer( - -min_distance_from_threat_to_target_buffer - wiggle.meters - ) - self._threat_tolerance = ThreatTolerance(target, target_size, wiggle) - self.threat_zones = self.threat_zones.difference(threat_mask) - - def nearest(self, point: Point) -> None: - if self.point_for_nearest_solution is not None: - raise RuntimeError("WaypointStrategy.nearest() called more than once") - self.point_for_nearest_solution = point - - def find(self) -> Point | None: - if self.point_for_nearest_solution is None: - raise RuntimeError( - "Must call WaypointStrategy.nearest() before WaypointStrategy.find()" - ) - - if not self.prerequisites_are_satisfied(): - return None - - try: - return nearest_points(self.allowed_area, self.point_for_nearest_solution)[0] - except ValueError: - # No solutions. - return None - - def iter_debug_info(self) -> Iterator[WaypointDebugInfo]: - yield from self.debug_infos - solution = self.find() - if solution is None: - return - yield WaypointDebugInfo("solution", solution) diff --git a/game/game.py b/game/game.py deleted file mode 100644 index f7716e219..000000000 --- a/game/game.py +++ /dev/null @@ -1,604 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import math -from collections.abc import Iterator -from datetime import date, datetime, time, timedelta -from typing import Any, List, TYPE_CHECKING, Type, Union, cast - -from dcs.countries import Switzerland, USAFAggressors, UnitedNationsPeacekeepers -from dcs.country import Country -from dcs.mapping import Point -from dcs.task import CAP, CAS, PinpointStrike -from dcs.vehicles import AirDefence -from faker import Faker - -from game.ato.closestairfields import ObjectiveDistanceCache -from game.models.game_stats import GameStats -from game.plugins import LuaPluginManager -from game.utils import Distance -from . import naming -from .ato.flighttype import FlightType -from .campaignloader import CampaignAirWingConfig -from .coalition import Coalition -from .db.gamedb import GameDb -from .infos.information import Information -from .lasercodes.lasercoderegistry import LaserCodeRegistry -from .persistence import SaveManager -from .profiling import logged_duration -from .settings import Settings -from .theater import ConflictTheater -from .theater.bullseye import Bullseye -from .theater.theatergroundobject import ( - EwrGroundObject, - SamGroundObject, - TheaterGroundObject, -) -from .theater.transitnetwork import TransitNetwork, TransitNetworkBuilder -from .timeofday import TimeOfDay -from .turnstate import TurnState -from .weather.conditions import Conditions - -if TYPE_CHECKING: - from .ato.airtaaskingorder import AirTaskingOrder - from .factions.faction import Faction - from .navmesh import NavMesh - from .sim import GameUpdateEvents - from .squadrons import AirWing - from .threatzones import ThreatZones - -COMMISION_UNIT_VARIETY = 4 -COMMISION_LIMITS_SCALE = 1.5 -COMMISION_LIMITS_FACTORS = { - PinpointStrike: 10, - CAS: 5, - CAP: 8, - AirDefence: 8, -} - -COMMISION_AMOUNTS_SCALE = 1.5 -COMMISION_AMOUNTS_FACTORS = { - PinpointStrike: 3, - CAS: 1, - CAP: 2, - AirDefence: 0.8, -} - -PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 30 -PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2 -PLAYER_BASEATTACK_THRESHOLD = 0.4 - -# amount of strength player bases recover for the turn -PLAYER_BASE_STRENGTH_RECOVERY = 0.2 - -# amount of strength enemy bases recover for the turn -ENEMY_BASE_STRENGTH_RECOVERY = 0.05 - -# cost of AWACS for single operation -AWACS_BUDGET_COST = 4 - -# Bonus multiplier logarithm base -PLAYER_BUDGET_IMPORTANCE_LOG = 2 - - -class Game: - def __init__( - self, - player_faction: Faction, - enemy_faction: Faction, - theater: ConflictTheater, - air_wing_config: CampaignAirWingConfig, - start_date: datetime, - start_time: time | None, - settings: Settings, - lua_plugin_manager: LuaPluginManager, - player_budget: float, - enemy_budget: float, - ) -> None: - self.settings = settings - self.lua_plugin_manager = lua_plugin_manager - self.theater = theater - self.turn = 0 - # NB: This is the *start* date. It is never updated. - self.date = date(start_date.year, start_date.month, start_date.day) - self.game_stats = GameStats() - self.notes = "" - self.informations: list[Information] = [] - self.message("Game Start", "-" * 40) - # Culling Zones are for areas around points of interest that contain things we may not wish to cull. - self.__culling_zones: List[Point] = [] - self.__destroyed_units: list[dict[str, Union[float, str]]] = [] - self.save_manager = SaveManager(self) - self.current_unit_id = 0 - self.current_group_id = 0 - self.name_generator = naming.namegen - self.laser_code_registry = LaserCodeRegistry() - - self.db = GameDb() - - if start_time is None: - self.time_of_day_offset_for_start_time = list(TimeOfDay).index( - TimeOfDay.Day - ) - else: - self.time_of_day_offset_for_start_time = list(TimeOfDay).index( - self.theater.daytime_map.best_guess_time_of_day_at(start_time) - ) - self.conditions = self.generate_conditions(forced_time=start_time) - - self.sanitize_sides(player_faction, enemy_faction) - self.blue = Coalition(self, player_faction, player_budget, player=True) - self.red = Coalition(self, enemy_faction, enemy_budget, player=False) - self.blue.set_opponent(self.red) - self.red.set_opponent(self.blue) - - for control_point in self.theater.controlpoints: - control_point.finish_init(self) - - self.blue.configure_default_air_wing(air_wing_config) - self.red.configure_default_air_wing(air_wing_config) - - self.on_load(game_still_initializing=True) - - def __setstate__(self, state: dict[str, Any]) -> None: - self.__dict__.update(state) - # Regenerate any state that was not persisted. - self.on_load() - - @property - def coalitions(self) -> Iterator[Coalition]: - yield self.blue - yield self.red - - def point_in_world(self, x: float, y: float) -> Point: - return Point(x, y, self.theater.terrain) - - def ato_for(self, player: bool) -> AirTaskingOrder: - return self.coalition_for(player).ato - - def transit_network_for(self, player: bool) -> TransitNetwork: - return self.coalition_for(player).transit_network - - def generate_conditions(self, forced_time: time | None = None) -> Conditions: - return Conditions.generate( - self.theater, - self.current_day, - self.current_turn_time_of_day, - self.settings, - forced_time=forced_time, - ) - - @staticmethod - def sanitize_sides(player_faction: Faction, enemy_faction: Faction) -> None: - """ - Make sure the opposing factions are using different countries - :return: - """ - if player_faction.country == enemy_faction.country: - if player_faction.country == "USA": - enemy_faction.country = "USAF Aggressors" - elif player_faction.country == "Russia": - enemy_faction.country = "USSR" - else: - enemy_faction.country = "Russia" - - def faction_for(self, player: bool) -> Faction: - return self.coalition_for(player).faction - - def faker_for(self, player: bool) -> Faker: - return self.coalition_for(player).faker - - def air_wing_for(self, player: bool) -> AirWing: - return self.coalition_for(player).air_wing - - def country_for(self, player: bool) -> str: - return self.coalition_for(player).country_name - - @property - def neutral_country(self) -> Type[Country]: - """Return the best fitting country that can be used as neutral faction in the generated mission""" - countries_in_use = [self.red.country_name, self.blue.country_name] - if UnitedNationsPeacekeepers not in countries_in_use: - return UnitedNationsPeacekeepers - elif Switzerland.name not in countries_in_use: - return Switzerland - else: - return USAFAggressors - - def coalition_for(self, player: bool) -> Coalition: - if player: - return self.blue - return self.red - - def adjust_budget(self, amount: float, player: bool) -> None: - self.coalition_for(player).adjust_budget(amount) - - def on_load(self, game_still_initializing: bool = False) -> None: - from .sim import GameUpdateEvents - - if not hasattr(self, "name_generator"): - self.name_generator = naming.namegen - # Hack: Replace the global name generator state with the state from the save - # game. - # - # We need to persist this state so that names generated after game load don't - # conflict with those generated before exit. - naming.namegen = self.name_generator - - # The installed plugins may have changed between runs. We need to load the - # current configuration and patch in the options that were previously set. - new_plugin_manager = LuaPluginManager.load() - new_plugin_manager.update_with(self.lua_plugin_manager) - self.lua_plugin_manager = new_plugin_manager - - ObjectiveDistanceCache.set_theater(self.theater) - self.compute_unculled_zones(GameUpdateEvents()) - if not game_still_initializing: - # We don't need to push events that happen during load. The UI will fully - # reset when we're done. - self.compute_threat_zones(GameUpdateEvents()) - - def finish_turn(self, events: GameUpdateEvents, skipped: bool = False) -> None: - """Finalizes the current turn and advances to the next turn. - - This handles the turn-end portion of passing a turn. Initialization of the next - turn is handled by `initialize_turn`. These are separate processes because while - turns may be initialized more than once under some circumstances (see the - documentation for `initialize_turn`), `finish_turn` performs the work that - should be guaranteed to happen only once per turn: - - * Turn counter increment. - * Delivering units ordered the previous turn. - * Transfer progress. - * Squadron replenishment. - * Income distribution. - * Base strength (front line position) adjustment. - * Weather/time-of-day generation. - - Some actions (like transit network assembly) will happen both here and in - `initialize_turn`. We need the network to be up to date so we can account for - base captures when processing the transfers that occurred last turn, but we also - need it to be up to date in the case of a re-initialization in `initialize_turn` - (such as to account for a cheat base capture) so that orders are only placed - where a supply route exists to the destination. This is a relatively cheap - operation so duplicating the effort is not a problem. - - Args: - skipped: True if the turn was skipped. - """ - self.message("End of turn #" + str(self.turn), "-" * 40) - self.turn += 1 - - # The coalition-specific turn finalization *must* happen before unit deliveries, - # since the coalition-specific finalization handles transit network updates and - # transfer processing. If in the other order, units may be delivered to captured - # bases, and freshly delivered units will spawn one leg through their journey. - self.blue.end_turn() - self.red.end_turn() - - for control_point in self.theater.controlpoints: - control_point.process_turn(self) - - if not skipped: - for cp in self.theater.player_points(): - for front_line in cp.front_lines.values(): - front_line.update_position() - events.update_front_line(front_line) - cp.base.affect_strength(+PLAYER_BASE_STRENGTH_RECOVERY) - - # We don't actually advance time or change the conditions between turn 0 and - # turn 1. - if self.turn > 1: - self.conditions = self.generate_conditions() - - def begin_turn_0(self) -> None: - """Initialization for the first turn of the game.""" - from .sim import GameUpdateEvents - - # Build the IADS Network - with logged_duration("Generate IADS Network"): - self.theater.iads_network.initialize_network(self.theater.ground_objects) - - for control_point in self.theater.controlpoints: - control_point.initialize_turn_0(self.laser_code_registry) - for tgo in control_point.connected_objectives: - self.db.tgos.add(tgo.id, tgo) - - # Correct the heading of specifc TGOs, can only be done after init turn 0 - for tgo in self.theater.ground_objects: - # If heading is 0 then we change the orientation to head towards the - # closest conflict. Heading of 0 means that the campaign designer wants - # to determine the heading automatically by liberation. Values other - # than 0 mean it is custom defined. - if tgo.should_head_to_conflict and tgo.heading.degrees == 0: - # Calculate the heading to conflict - heading = self.theater.heading_to_conflict_from(tgo.position) - # Rotate the whole TGO with the new heading - tgo.rotate(heading or tgo.heading) - - self.blue.preinit_turn_0() - self.red.preinit_turn_0() - # TODO: Check for overfull bases. - # We don't need to actually stream events for turn zero because we haven't given - # *any* state to the UI yet, so it will need to do a full draw once we do. - self.initialize_turn(GameUpdateEvents()) - - def save_last_turn_state(self) -> None: - self.save_manager.save_last_turn() - - def pass_turn(self, no_action: bool = False) -> None: - """Ends the current turn and initializes the new turn. - - Called both when skipping a turn or by ending the turn as the result of combat. - - Args: - no_action: True if the turn was skipped. - """ - from .server import EventStream - from .sim import GameUpdateEvents - - if no_action: - # Only save the last turn state if the turn was skipped. Otherwise, we'll - # end up saving the game after we've already applied the results, making - # this useless... - self.save_manager.save_last_turn() - - events = GameUpdateEvents() - - logging.info("Pass turn") - with logged_duration("Turn finalization"): - self.finish_turn(events, no_action) - - with logged_duration("Turn initialization"): - self.initialize_turn(events) - - EventStream.put_nowait(events) - - self.save_manager.save_start_of_turn() - - def check_win_loss(self) -> TurnState: - player_airbases = { - cp for cp in self.theater.player_points() if cp.runway_is_operational() - } - if not player_airbases: - return TurnState.LOSS - - enemy_airbases = { - cp for cp in self.theater.enemy_points() if cp.runway_is_operational() - } - if not enemy_airbases: - return TurnState.WIN - - return TurnState.CONTINUE - - def set_bullseye(self) -> None: - player_cp, enemy_cp = self.theater.closest_opposing_control_points() - self.blue.bullseye = Bullseye(enemy_cp.position) - self.red.bullseye = Bullseye(player_cp.position) - - def initialize_turn( - self, - events: GameUpdateEvents, - for_red: bool = True, - for_blue: bool = True, - ) -> None: - """Performs turn initialization for the specified players. - - Turn initialization performs all of the beginning-of-turn actions. *End-of-turn* - processing happens in `pass_turn` (despite the name, it's called both for - skipping the turn and ending the turn after combat). - - Special care needs to be taken here because initialization can occur more than - once per turn. A number of events can require re-initializing a turn: - - * Cheat capture. Bases changing hands invalidates many missions in both ATOs, - purchase orders, threat zones, transit networks, etc. Practically speaking, - after a base capture the turn needs to be treated as fully new. The game might - even be over after a capture. - * Cheat front line position. CAS missions are no longer in the correct location, - and the ground planner may also need changes. - * Selling/buying units at TGOs. Selling a TGO might leave missions in the ATO - with invalid targets. Buying a new SAM (or even replacing some units in a SAM) - potentially changes the threat zone and may alter mission priorities and - flight planning. - - Most of the work is delegated to initialize_turn_for, which handles the - coalition-specific turn initialization. In some cases only one coalition will be - (re-) initialized. This is the case when buying or selling TGO units, since we - don't want to force the player to redo all their planning just because they - repaired a SAM, but should replan opfor when that happens. On the other hand, - base captures are significant enough (and likely enough to be the first thing - the player does in a turn) that we replan blue as well. Front lines are less - impactful but also likely to be early, so they also cause a blue replan. - - Args: - events: Game update event container for turn initialization. - for_red: True if opfor should be re-initialized. - for_blue: True if the player coalition should be re-initialized. - """ - self.set_bullseye() - - # Update statistics - self.game_stats.update(self) - - # Check for win or loss condition - turn_state = self.check_win_loss() - if turn_state in (TurnState.LOSS, TurnState.WIN): - return self.process_win_loss(turn_state) - - # Plan flights & combat for next turn - with logged_duration("Threat zone computation"): - self.compute_threat_zones(events) - - # Plan Coalition specific turn - if for_blue: - self.blue.initialize_turn(self.turn == 0) - if for_red: - self.red.initialize_turn(self.turn == 0) - - # Update cull zones - with logged_duration("Computing culling positions"): - self.compute_unculled_zones(events) - - events.begin_new_turn() - - def message(self, title: str, text: str = "") -> None: - self.informations.append(Information(title, text, turn=self.turn)) - - @property - def current_turn_time_of_day(self) -> TimeOfDay: - tod_turn = max(0, self.turn - 1) + self.time_of_day_offset_for_start_time - return list(TimeOfDay)[tod_turn % 4] - - @property - def current_day(self) -> date: - return self.date + timedelta(days=self.turn // 4) - - def next_unit_id(self) -> int: - """ - Next unit id for pre-generated units - """ - self.current_unit_id += 1 - return self.current_unit_id - - def next_group_id(self) -> int: - """ - Next unit id for pre-generated units - """ - self.current_group_id += 1 - return self.current_group_id - - def compute_transit_network_for(self, player: bool) -> TransitNetwork: - return TransitNetworkBuilder(self.theater, player).build() - - def compute_threat_zones(self, events: GameUpdateEvents) -> None: - self.blue.compute_threat_zones(events) - self.red.compute_threat_zones(events) - self.blue.compute_nav_meshes(events) - self.red.compute_nav_meshes(events) - - def threat_zone_for(self, player: bool) -> ThreatZones: - return self.coalition_for(player).threat_zone - - def navmesh_for(self, player: bool) -> NavMesh: - return self.coalition_for(player).nav_mesh - - def compute_unculled_zones(self, events: GameUpdateEvents) -> None: - """ - Compute the current conflict position(s) used for culling calculation - """ - from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, - ) - - zones = [] - - # By default, use the existing frontline conflict position - for front_line in self.theater.conflicts(): - position = FrontLineConflictDescription.frontline_position( - front_line, self.theater - ) - zones.append(position[0]) - zones.append(front_line.blue_cp.position) - zones.append(front_line.red_cp.position) - - for cp in self.theater.controlpoints: - # If do_not_cull_carrier is enabled, add carriers as culling point - if self.settings.perf_do_not_cull_carrier: - if cp.is_carrier or cp.is_lha: - zones.append(cp.position) - - # If there is no conflict take the center point between the two nearest opposing bases - if len(zones) == 0: - cpoint = None - min_distance = math.inf - for cp in self.theater.player_points(): - for cp2 in self.theater.enemy_points(): - d = cp.position.distance_to_point(cp2.position) - if d < min_distance: - min_distance = d - cpoint = cp.position.midpoint(cp2.position) - zones.append(cp.position) - zones.append(cp2.position) - break - if cpoint is not None: - break - if cpoint is not None: - zones.append(cpoint) - - packages = itertools.chain(self.blue.ato.packages, self.red.ato.packages) - for package in packages: - if package.primary_task is FlightType.BARCAP: - # BARCAPs will be planned at most locations on smaller theaters, - # rendering culling fairly useless. BARCAP packages don't really - # need the ground detail since they're defensive. SAMs nearby - # are only interesting if there are enemies in the area, and if - # there are they won't be culled because of the enemy's mission. - continue - zones.append(package.target.position) - - self.__culling_zones = zones - events.update_unculled_zones(zones) - - def add_destroyed_units(self, data: dict[str, Union[float, str]]) -> None: - pos = Point( - cast(float, data["x"]), cast(float, data["z"]), self.theater.terrain - ) - if self.theater.is_on_land(pos): - self.__destroyed_units.append(data) - - def get_destroyed_units(self) -> list[dict[str, Union[float, str]]]: - return self.__destroyed_units - - def position_culled(self, pos: Point) -> bool: - """ - Check if unit can be generated at given position depending on culling performance settings - :param pos: Position you are tryng to spawn stuff at - :return: True if units can not be added at given position - """ - if not self.settings.perf_culling: - return False - for z in self.__culling_zones: - if z.distance_to_point(pos) < self.settings.perf_culling_distance * 1000: - return False - return True - - def iads_considerate_culling(self, tgo: TheaterGroundObject) -> bool: - if not self.settings.perf_do_not_cull_threatening_iads: - return self.position_culled(tgo.position) - else: - if self.settings.perf_culling: - if isinstance(tgo, EwrGroundObject): - max_detection_range = tgo.max_detection_range().meters - for z in self.__culling_zones: - seperation = z.distance_to_point(tgo.position) - # Don't cull EWR if in detection range. - if seperation < max_detection_range: - return False - if isinstance(tgo, SamGroundObject): - max_threat_range = tgo.max_threat_range().meters - for z in self.__culling_zones: - seperation = z.distance_to_point(tgo.position) - # Create a 12nm buffer around nearby SAMs. - respect_bubble = ( - max_threat_range + Distance.from_nautical_miles(12).meters - ) - if seperation < respect_bubble: - return False - return self.position_culled(tgo.position) - - def get_culling_zones(self) -> list[Point]: - """ - Check culling points - :return: List of culling zones - """ - return self.__culling_zones - - def process_win_loss(self, turn_state: TurnState) -> None: - if turn_state is TurnState.WIN: - self.message( - "Congratulations, you are victorious! Start a new campaign to continue." - ) - elif turn_state is TurnState.LOSS: - self.message("Game Over, you lose. Start a new campaign to continue.") diff --git a/game/ground_forces/__init__.py b/game/ground_forces/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/ground_forces/ai_ground_planner.py b/game/ground_forces/ai_ground_planner.py deleted file mode 100644 index 5a58671b2..000000000 --- a/game/ground_forces/ai_ground_planner.py +++ /dev/null @@ -1,161 +0,0 @@ -from __future__ import annotations - -import logging -import random -from enum import Enum -from typing import List, TYPE_CHECKING -from uuid import UUID - -from game.data.units import UnitClass -from game.dcs.groundunittype import GroundUnitType -from .combat_stance import CombatStance - -if TYPE_CHECKING: - from game import Game - from game.theater import ControlPoint - -MAX_COMBAT_GROUP_PER_CP = 10 - - -class CombatGroupRole(Enum): - TANK = 1 - APC = 2 - IFV = 3 - ARTILLERY = 4 - SHORAD = 5 - LOGI = 6 - INFANTRY = 7 - ATGM = 8 - RECON = 9 - - -DISTANCE_FROM_FRONTLINE = { - CombatGroupRole.TANK: (2200, 3200), - CombatGroupRole.APC: (2700, 3700), - CombatGroupRole.IFV: (2700, 3700), - CombatGroupRole.ARTILLERY: (16000, 18000), - CombatGroupRole.SHORAD: (5000, 8000), - CombatGroupRole.LOGI: (18000, 20000), - CombatGroupRole.INFANTRY: (2800, 3300), - CombatGroupRole.ATGM: (5200, 6200), - CombatGroupRole.RECON: (2000, 3000), -} - -GROUP_SIZES_BY_COMBAT_STANCE = { - CombatStance.DEFENSIVE: [2, 4, 6], - CombatStance.AGGRESSIVE: [2, 4, 6], - CombatStance.RETREAT: [2, 4, 6, 8], - CombatStance.BREAKTHROUGH: [4, 6, 6, 8], - CombatStance.ELIMINATION: [2, 4, 4, 4, 6], - CombatStance.AMBUSH: [1, 1, 2, 2, 2, 2, 4], -} - - -class CombatGroup: - def __init__( - self, role: CombatGroupRole, unit_type: GroundUnitType, size: int - ) -> None: - self.unit_type = unit_type - self.size = size - self.role = role - self.start_position = None - - def __str__(self) -> str: - s = f"ROLE : {self.role}\n" - if self.size: - s += f"UNITS {self.unit_type} * {self.size}" - return s - - -class GroundPlanner: - def __init__(self, cp: ControlPoint, game: Game) -> None: - self.cp = cp - self.game = game - self.connected_enemy_cp = [ - cp for cp in self.cp.connected_points if cp.captured != self.cp.captured - ] - self.tank_groups: List[CombatGroup] = [] - self.apc_group: List[CombatGroup] = [] - self.ifv_group: List[CombatGroup] = [] - self.art_group: List[CombatGroup] = [] - self.atgm_group: List[CombatGroup] = [] - self.logi_groups: List[CombatGroup] = [] - self.shorad_groups: List[CombatGroup] = [] - self.recon_groups: List[CombatGroup] = [] - - self.units_per_cp: dict[UUID, List[CombatGroup]] = {} - for cp in self.connected_enemy_cp: - self.units_per_cp[cp.id] = [] - self.reserve: List[CombatGroup] = [] - - def plan_groundwar(self) -> None: - ground_unit_limit = self.cp.frontline_unit_count_limit - - remaining_available_frontline_units = ground_unit_limit - - # TODO: Fix to handle the per-front stances. - # https://github.com/dcs-liberation/dcs_liberation/issues/1417 - group_size_choice = GROUP_SIZES_BY_COMBAT_STANCE[CombatStance.DEFENSIVE] - - # Create combat groups and assign them randomly to each enemy CP - for unit_type in self.cp.base.armor: - unit_class = unit_type.unit_class - if unit_class is UnitClass.TANK: - collection = self.tank_groups - role = CombatGroupRole.TANK - elif unit_class is UnitClass.APC: - collection = self.apc_group - role = CombatGroupRole.APC - elif unit_class is UnitClass.ARTILLERY: - collection = self.art_group - role = CombatGroupRole.ARTILLERY - elif unit_class is UnitClass.IFV: - collection = self.ifv_group - role = CombatGroupRole.IFV - elif unit_class is UnitClass.LOGISTICS: - collection = self.logi_groups - role = CombatGroupRole.LOGI - elif unit_class is UnitClass.ATGM: - collection = self.atgm_group - role = CombatGroupRole.ATGM - elif unit_class in [UnitClass.SHORAD, UnitClass.AAA]: - collection = self.shorad_groups - role = CombatGroupRole.SHORAD - elif unit_class is UnitClass.RECON: - collection = self.recon_groups - role = CombatGroupRole.RECON - else: - logging.warning( - f"Unused front line vehicle at base {unit_type}: unknown unit class" - ) - continue - - available = self.cp.base.armor[unit_type] - - if available > remaining_available_frontline_units: - available = remaining_available_frontline_units - - remaining_available_frontline_units -= available - - while available > 0: - if role == CombatGroupRole.SHORAD: - count = 1 - else: - count = random.choice(group_size_choice) - if count > available: - if available >= 2: - count = 2 - else: - count = 1 - available -= count - - group = CombatGroup(role, unit_type, count) - if len(self.connected_enemy_cp) > 0: - enemy_cp = random.choice(self.connected_enemy_cp).id - self.units_per_cp[enemy_cp].append(group) - else: - self.reserve.append(group) - collection.append(group) - - if remaining_available_frontline_units == 0: - break diff --git a/game/ground_forces/combat_stance.py b/game/ground_forces/combat_stance.py deleted file mode 100644 index 26e959eb3..000000000 --- a/game/ground_forces/combat_stance.py +++ /dev/null @@ -1,12 +0,0 @@ -from enum import Enum - - -class CombatStance(Enum): - DEFENSIVE = 0 # Unit will adopt defensive stance with medium group of units - AGGRESSIVE = ( - 1 # Unit will attempt to make progress with medium sized group of units - ) - RETREAT = 2 # Unit will retreat - BREAKTHROUGH = 3 # Unit will attempt a breakthrough, rushing forward very aggresively with big group of armored units, and even less armored units will move aggresively - ELIMINATION = 4 # Unit will progress aggresively toward anemy units, attempting to eliminate the ennemy force - AMBUSH = 5 # Units will adopt a defensive stance a bit different from 'DEFENSIVE', ATGM & INFANTRY with RPG will be located on frontline with the armored units. (The groups of units will be smaller) diff --git a/game/groundunitorders.py b/game/groundunitorders.py deleted file mode 100644 index b6644527a..000000000 --- a/game/groundunitorders.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from datetime import datetime -from typing import Optional, TYPE_CHECKING - -from game.theater import ControlPoint -from .coalition import Coalition -from .dcs.groundunittype import GroundUnitType -from .theater.transitnetwork import ( - NoPathError, - TransitNetwork, -) -from .transfers import TransferOrder - -if TYPE_CHECKING: - from .game import Game - - -class GroundUnitOrders: - def __init__(self, destination: ControlPoint) -> None: - self.destination = destination - - # Maps unit type to order quantity. - self.units: dict[GroundUnitType, int] = defaultdict(int) - - def __str__(self) -> str: - return f"Pending ground unit delivery to {self.destination}" - - def order(self, units: dict[GroundUnitType, int]) -> None: - for k, v in units.items(): - self.units[k] += v - - def sell(self, units: dict[GroundUnitType, int]) -> None: - for k, v in units.items(): - self.units[k] -= v - if self.units[k] == 0: - del self.units[k] - - def refund_all(self, coalition: Coalition) -> None: - self._refund(coalition, self.units) - self.units = defaultdict(int) - - def _refund(self, coalition: Coalition, units: dict[GroundUnitType, int]) -> None: - for unit_type, count in units.items(): - logging.info(f"Refunding {count} {unit_type} at {self.destination.name}") - coalition.adjust_budget(unit_type.price * count) - - def pending_orders(self, unit_type: GroundUnitType) -> int: - pending_units = self.units.get(unit_type) - if pending_units is None: - pending_units = 0 - return pending_units - - def process(self, game: Game, now: datetime) -> None: - coalition = game.coalition_for(self.destination.captured) - ground_unit_source = self.find_ground_unit_source(game) - if ground_unit_source is None: - game.message( - f"{self.destination.name} lost its source for ground unit " - "reinforcements. Refunding purchase price." - ) - self.refund_all(coalition) - - bought_units: dict[GroundUnitType, int] = {} - units_needing_transfer: dict[GroundUnitType, int] = {} - for unit_type, count in self.units.items(): - allegiance = "Ally" if self.destination.captured else "Enemy" - d: dict[GroundUnitType, int] - if self.destination != ground_unit_source: - source = ground_unit_source - d = units_needing_transfer - else: - source = self.destination - d = bought_units - - if count < 0: - logging.error( - f"Attempted sale of {unit_type} at {self.destination} but ground " - "units cannot be sold" - ) - elif count > 0: - d[unit_type] = count - game.message( - f"{allegiance} reinforcements: {unit_type} x {count} at {source}" - ) - - self.units = defaultdict(int) - self.destination.base.commission_units(bought_units) - - if units_needing_transfer: - if ground_unit_source is None: - raise RuntimeError( - f"Ground unit source could not be found for {self.destination} but " - "still tried to transfer units to there" - ) - ground_unit_source.base.commission_units(units_needing_transfer) - self.create_transfer( - coalition, ground_unit_source, units_needing_transfer, now - ) - - def create_transfer( - self, - coalition: Coalition, - source: ControlPoint, - units: dict[GroundUnitType, int], - now: datetime, - ) -> None: - coalition.transfers.new_transfer( - TransferOrder(source, self.destination, units), now - ) - - def find_ground_unit_source(self, game: Game) -> Optional[ControlPoint]: - # This is running *after* the turn counter has been incremented, so this is the - # reaction to turn 0. On turn zero we allow units to be recruited anywhere for - # delivery on turn 1 so that turn 1 always starts with units on the front line. - if game.turn == 1: - return self.destination - - # Fast path if the destination is a valid source. - if self.destination.can_recruit_ground_units(game): - return self.destination - - try: - return self.find_ground_unit_source_in_network( - game.transit_network_for(self.destination.captured), game - ) - except NoPathError: - return None - - def find_ground_unit_source_in_network( - self, network: TransitNetwork, game: Game - ) -> Optional[ControlPoint]: - sources = [] - for control_point in game.theater.control_points_for(self.destination.captured): - if control_point.can_recruit_ground_units( - game - ) and network.has_path_between(self.destination, control_point): - sources.append(control_point) - - if not sources: - return None - - # Fast path to skip the distance calculation if we have only one option. - if len(sources) == 1: - return sources[0] - - closest = sources[0] - _, cost = network.shortest_path_with_cost(self.destination, closest) - for source in sources: - _, new_cost = network.shortest_path_with_cost(self.destination, source) - if new_cost < cost: - closest = source - cost = new_cost - return closest diff --git a/game/htn.py b/game/htn.py deleted file mode 100644 index ae145262d..000000000 --- a/game/htn.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections import deque -from collections.abc import Iterator, Sequence -from dataclasses import dataclass -from typing import Any, Generic, Optional, TypeVar - -WorldStateT = TypeVar("WorldStateT", bound="WorldState[Any]") - - -class WorldState(ABC, Generic[WorldStateT]): - @abstractmethod - def clone(self) -> WorldStateT: - ... - - -class Task(Generic[WorldStateT]): - pass - - -Method = Sequence[Task[WorldStateT]] - - -class PrimitiveTask(Task[WorldStateT], Generic[WorldStateT], ABC): - @abstractmethod - def preconditions_met(self, state: WorldStateT) -> bool: - ... - - @abstractmethod - def apply_effects(self, state: WorldStateT) -> None: - ... - - -class CompoundTask(Task[WorldStateT], Generic[WorldStateT], ABC): - @abstractmethod - def each_valid_method(self, state: WorldStateT) -> Iterator[Method[WorldStateT]]: - ... - - -PrimitiveTaskT = TypeVar("PrimitiveTaskT", bound=PrimitiveTask[Any]) - - -@dataclass -class PlanningState(Generic[WorldStateT, PrimitiveTaskT]): - state: WorldStateT - tasks_to_process: deque[Task[WorldStateT]] - plan: list[PrimitiveTaskT] - methods: Optional[Iterator[Method[WorldStateT]]] - - -@dataclass(frozen=True) -class PlanningResult(Generic[WorldStateT, PrimitiveTaskT]): - tasks: list[PrimitiveTaskT] - end_state: WorldStateT - - -class PlanningHistory(Generic[WorldStateT, PrimitiveTaskT]): - def __init__(self) -> None: - self.states: list[PlanningState[WorldStateT, PrimitiveTaskT]] = [] - - def push(self, planning_state: PlanningState[WorldStateT, PrimitiveTaskT]) -> None: - self.states.append(planning_state) - - def pop(self) -> PlanningState[WorldStateT, PrimitiveTaskT]: - return self.states.pop() - - -class Planner(Generic[WorldStateT, PrimitiveTaskT]): - def __init__(self, main_task: Task[WorldStateT]) -> None: - self.main_task = main_task - - def plan( - self, initial_state: WorldStateT - ) -> Optional[PlanningResult[WorldStateT, PrimitiveTaskT]]: - planning_state: PlanningState[WorldStateT, PrimitiveTaskT] = PlanningState( - initial_state, deque([self.main_task]), [], None - ) - history: PlanningHistory[WorldStateT, PrimitiveTaskT] = PlanningHistory() - while planning_state.tasks_to_process: - task = planning_state.tasks_to_process.popleft() - if isinstance(task, PrimitiveTask): - if task.preconditions_met(planning_state.state): - task.apply_effects(planning_state.state) - # Ignore type erasure. We've already verified that this is a Planner - # with a WorldStateT and a PrimitiveTaskT, so we know that the task - # list is a list of CompoundTask[WorldStateT] and PrimitiveTaskT. We - # could scatter more unions throughout to be more explicit but - # there's no way around the type erasure that mypy uses for - # isinstance. - planning_state.plan.append(task) # type: ignore - else: - planning_state = history.pop() - else: - assert isinstance(task, CompoundTask) - # If the methods field of our current state is not None that means we're - # resuming a prior attempt to execute this task after a subtask of the - # previously selected method failed. - # - # Otherwise this is the first exectution of this task so we need to - # create the generator. - if planning_state.methods is None: - methods = task.each_valid_method(planning_state.state) - else: - methods = planning_state.methods - try: - method = next(methods) - # Push the current node back onto the stack so that we resume - # handling this task when we pop back to this state. - resume_tasks: deque[Task[WorldStateT]] = deque([task]) - resume_tasks.extend(planning_state.tasks_to_process) - history.push( - PlanningState( - planning_state.state.clone(), - resume_tasks, - planning_state.plan, - methods, - ) - ) - planning_state.methods = None - planning_state.tasks_to_process.extendleft(reversed(method)) - except StopIteration: - try: - planning_state = history.pop() - except IndexError: - # No valid plan was found. - return None - return PlanningResult(planning_state.plan, planning_state.state) diff --git a/game/income.py b/game/income.py deleted file mode 100644 index 729ecd7aa..000000000 --- a/game/income.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import TYPE_CHECKING - -from game.config import REWARDS - -if TYPE_CHECKING: - from game import Game - - -@dataclass(frozen=True) -class BuildingIncome: - name: str - category: str - number: int - income_per_building: float - - @property - def income(self) -> float: - return self.number * self.income_per_building - - -class Income: - def __init__(self, game: Game, player: bool) -> None: - if player: - self.multiplier = game.settings.player_income_multiplier - else: - self.multiplier = game.settings.enemy_income_multiplier - self.control_points = [] - self.buildings = [] - - for cp in game.theater.control_points_for(player): - if cp.income_per_turn: - self.control_points.append(cp) - - for tgo in cp.ground_objects: - if tgo.category not in REWARDS: - continue - self.buildings.append( - BuildingIncome( - tgo.obj_name, - tgo.category, - sum(1 for b in tgo.statics if b.alive), - REWARDS[tgo.category], - ) - ) - - self.from_bases = sum(cp.income_per_turn for cp in self.control_points) - self.total_buildings = sum(b.income for b in self.buildings) - self.total = (self.total_buildings + self.from_bases) * self.multiplier diff --git a/game/infos/information.py b/game/infos/information.py deleted file mode 100644 index efc3fb968..000000000 --- a/game/infos/information.py +++ /dev/null @@ -1,19 +0,0 @@ -import datetime - - -class Information: - def __init__(self, title: str = "", text: str = "", turn: int = 0) -> None: - self.title = title - self.text = text - self.turn = turn - self.timestamp = datetime.datetime.now() - - def __str__(self) -> str: - return "[{}][{}] {} {}".format( - self.timestamp.strftime("%Y-%m-%d %H:%M:%S") - if self.timestamp is not None - else "", - self.turn, - self.title, - self.text, - ) diff --git a/game/lasercodes/__init__.py b/game/lasercodes/__init__.py deleted file mode 100644 index 1361ef6d7..000000000 --- a/game/lasercodes/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .ilasercoderegistry import ILaserCodeRegistry -from .lasercode import LaserCode -from .lasercoderegistry import LaserCodeRegistry diff --git a/game/lasercodes/ilasercoderegistry.py b/game/lasercodes/ilasercoderegistry.py deleted file mode 100644 index e59a9d666..000000000 --- a/game/lasercodes/ilasercoderegistry.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from .lasercode import LaserCode - - -class ILaserCodeRegistry(ABC): - @abstractmethod - def alloc_laser_code(self) -> LaserCode: - ... - - @abstractmethod - def release_code(self, code: LaserCode) -> None: - ... diff --git a/game/lasercodes/lasercode.py b/game/lasercodes/lasercode.py deleted file mode 100644 index c80cf5db0..000000000 --- a/game/lasercodes/lasercode.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from .ilasercoderegistry import ILaserCodeRegistry - - -class LaserCode: - def __init__(self, code: int, registry: ILaserCodeRegistry) -> None: - self.verify_laser_code(code) - self.code = code - self.registry = registry - - def release(self) -> None: - self.registry.release_code(self) - - @staticmethod - def verify_laser_code(code: int) -> None: - # https://forum.dcs.world/topic/211574-valid-laser-codes/ - # Valid laser codes are as follows - # First digit is always 1 - # Second digit is 5-7 - # Third and fourth digits are 1 - 8 - # We iterate backward (reversed()) so that 1687 follows 1688 - - # Special case used by FC3 aircraft like the A-10A that is not valid for other - # aircraft. - if code == 1113: - return - - # Must be 4 digits with no leading 0 - if code < 1000 or code >= 2000: - raise ValueError - - # The first digit was already verified above. Isolate the remaining three - # digits. The resulting list is ordered by significance, not printed position. - digits = [code // 10**i % 10 for i in range(3)] - - if digits[0] < 1 or digits[0] > 8: - raise ValueError - if digits[1] < 1 or digits[1] > 8: - raise ValueError - if digits[2] < 5 or digits[2] > 7: - raise ValueError - - def __str__(self) -> str: - return f"{self.code}" - - def __eq__(self, other: object) -> bool: - if not isinstance(other, LaserCode): - return False - return self.code == other.code - - def __hash__(self) -> int: - return hash(self.code) diff --git a/game/lasercodes/lasercoderegistry.py b/game/lasercodes/lasercoderegistry.py deleted file mode 100644 index 7913de1af..000000000 --- a/game/lasercodes/lasercoderegistry.py +++ /dev/null @@ -1,42 +0,0 @@ -import logging -from collections import deque - -from .ilasercoderegistry import ILaserCodeRegistry -from .lasercode import LaserCode - - -class LaserCodeRegistry(ILaserCodeRegistry): - def __init__(self) -> None: - self.allocated_codes: set[int] = set() - self.available_codes = LaserCodeRegistry._all_valid_laser_codes() - self.fc3_code = LaserCode(1113, self) - - def alloc_laser_code(self) -> LaserCode: - try: - code = self.available_codes.popleft() - self.allocated_codes.add(code) - return LaserCode(code, self) - except IndexError: - raise RuntimeError("All laser codes have been allocated") - - def release_code(self, code: LaserCode) -> None: - if code.code in self.allocated_codes: - self.allocated_codes.remove(code.code) - self.available_codes.appendleft(code.code) - else: - logging.error( - "attempted to release laser code %d which was not allocated", code.code - ) - - @staticmethod - def _all_valid_laser_codes() -> deque[int]: - # Valid laser codes are as follows - # First digit is always 1 - # Second digit is 5-7 - # Third and fourth digits are 1 - 8 - # We iterate backward (reversed()) so that 1687 follows 1688 - q = deque(int(oct(code)[2:]) + 11 for code in reversed(range(0o1500, 0o2000))) - - # We start with the default of 1688 and wrap around when we reach the end - q.rotate(-q.index(1688)) - return q diff --git a/game/layout/__init__.py b/game/layout/__init__.py deleted file mode 100644 index a458aa4da..000000000 --- a/game/layout/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .layout import TgoLayout, TgoLayoutGroup, TgoLayoutUnitGroup -from .layoutloader import LayoutLoader - -LAYOUTS = LayoutLoader() diff --git a/game/layout/layout.py b/game/layout/layout.py deleted file mode 100644 index 08fb18798..000000000 --- a/game/layout/layout.py +++ /dev/null @@ -1,317 +0,0 @@ -from __future__ import annotations -from collections import defaultdict - -import logging -import random -from dataclasses import dataclass, field -from typing import TYPE_CHECKING, Iterator, Type, Optional - -from dcs import Point -from dcs.unit import Unit -from dcs.unittype import UnitType as DcsUnitType - -from game.data.groups import GroupRole, GroupTask -from game.data.units import UnitClass -from game.theater.iadsnetwork.iadsrole import IadsRole -from game.theater.presetlocation import PresetLocation -from game.theater.theatergroundobject import ( - IadsBuildingGroundObject, - SamGroundObject, - EwrGroundObject, - BuildingGroundObject, - MissileSiteGroundObject, - ShipGroundObject, - CarrierGroundObject, - LhaGroundObject, - CoastalSiteGroundObject, - VehicleGroupGroundObject, - IadsGroundObject, -) -from game.theater.theatergroup import TheaterUnit -from game.utils import Heading - -if TYPE_CHECKING: - from game.factions.faction import Faction - from game.theater.theatergroundobject import TheaterGroundObject - from game.theater.controlpoint import ControlPoint - - -class LayoutException(Exception): - pass - - -@dataclass -class LayoutUnit: - """The Position and Orientation of a single unit within the GroupLayout""" - - name: str - position: Point - heading: int - - @staticmethod - def from_unit(unit: Unit) -> LayoutUnit: - """Creates a LayoutUnit from a DCS Unit""" - return LayoutUnit( - unit.name, - unit.position, - int(unit.heading), - ) - - -@dataclass -class TgoLayoutGroup: - """The layout of a group which will generate a DCS group later. The TgoLayoutGroup has one or many TgoLayoutUnitGroup which represents a set of unit of the same type. Therefore the TgoLayoutGroup is a logical grouping of different unit_types. A TgoLayout can have one or many TgoLayoutGroup""" - - # The group name which will be used later as the DCS group name - group_name: str - - # The index of the group within the TgoLayout. Used to preserve that the order of - # the groups generated match the order defined in the layout yaml. - group_index: int - - # List of all connected TgoLayoutUnitGroup - unit_groups: list[TgoLayoutUnitGroup] = field(default_factory=list) - - -@dataclass -class TgoLayoutUnitGroup: - """The layout of a single type of unit within the TgoLayout - - Each DCS group that is spawned in the mission is composed of one or more - TgoLayoutGroup. Each TgoLayoutGroup will generate only a single type of unit. - - The merging of multiple TgoLayoutGroups to a single DCS group is defined in the - TgoLayout with a dict which uses the Dcs group name as key and the corresponding - TgoLayoutGroups as values. - - Each TgoLayoutGroup will be filled with a single type of unit when generated. The - types compatible with the position can either be specified precisely (with - unit_types) or generically (with unit_classes). If neither list specifies units - that can be fulfilled by the faction, fallback_classes will be used. This allows - the early-warning radar template, which prefers units that are defined as early - warning radars like the 55G6, but to fall back to any radar usable by the faction - if EWRs are not available. - - A TgoLayoutGroup may be optional. Factions or ForceGroups that are not able to - provide an actual unit for the TgoLayoutGroup will still be able to use the layout; - the optional TgoLayoutGroup will be omitted. - """ - - name: str - layout_units: list[LayoutUnit] - - # Define the amount of units to be created. This can be a fixed int or a random - # choice from a range of two ints. If the list is empty it will use the whole group - # size / all available LayoutUnits - unit_count: list[int] = field(default_factory=list) - - # defintion which unit types are supported - unit_types: list[Type[DcsUnitType]] = field(default_factory=list) - unit_classes: list[UnitClass] = field(default_factory=list) - fallback_classes: list[UnitClass] = field(default_factory=list) - - # The index of the TgoLayoutGroup within the Layout - unit_index: int = field(default_factory=int) - - # Allows a group to have a special SubTask (PointDefence for example) - sub_task: Optional[GroupTask] = None - - # Defines if this groupTemplate is required or not - optional: bool = False - - # Should this be filled by accessible units if optional or not - fill: bool = True - - def possible_types_for_faction(self, faction: Faction) -> list[Type[DcsUnitType]]: - """Determine the possible dcs unit types for the TgoLayoutGroup and the given faction""" - unit_types = [t for t in self.unit_types if faction.has_access_to_dcs_type(t)] - - alternative_types = [] - for accessible_unit in faction.accessible_units: - if accessible_unit.unit_class in self.unit_classes: - unit_types.append(accessible_unit.dcs_unit_type) - if accessible_unit.unit_class in self.fallback_classes: - alternative_types.append(accessible_unit.dcs_unit_type) - - if not unit_types and not alternative_types and not self.optional: - raise LayoutException(f"{self.name} not usable by faction {faction.name}") - - return unit_types or alternative_types - - @property - def group_size(self) -> int: - """The amount of units to be generated. If unit_count is defined in the layout this will be randomized accordingly. Otherwise this will be the maximum size.""" - if self.unit_count: - if len(self.unit_count) == 1: - return self.unit_count[0] - return random.choice(range(min(self.unit_count), max(self.unit_count))) - return self.max_size - - @property - def max_size(self) -> int: - return len(self.layout_units) - - def generate_units( - self, go: TheaterGroundObject, unit_type: Type[DcsUnitType], amount: int - ) -> list[TheaterUnit]: - """Generate units of the given unit type and amount for the TgoLayoutGroup""" - if amount > len(self.layout_units): - raise LayoutException( - f"{self.name} has incorrect unit_count for {unit_type.id}" - ) - return [ - TheaterUnit.from_template(i, unit_type, self.layout_units[i], go) - for i in range(amount) - ] - - -class TgoLayout: - """TgoLayout defines how a TheaterGroundObject will be generated from a ForceGroup. This defines the positioning, orientation, type and amount of the actual units - - Each TgoLayout is defined in resources/layouts with a .yaml file which has all the - information about the Layout next to a .miz file which gives information about the - actual position (x, y) and orientation (heading) of the units. The layout file also - defines the structure of the DCS group (or groups) that will be spawned in the - mission. Complex groups like SAMs protected by point-defense require specific - grouping when used with plugins like Skynet. One group would define the main - battery (the search and track radars, launchers, C2 units, etc), another would - define PD units, and others could define SHORADs or resupply units. - - Each group (representing a DCS group) is further divided into TgoLayoutGroups. As - a TgoLayoutGroup only represents a single dcs unit type the logical dcs group of multiple unit types will be created with the usage of a dict which has the DCS Group name as key and a list of TgoLayoutGroups which will be merged into this single dcs group. - - As the TgoLayout will be used to create a TheaterGroundObject for a ForceGroup, - specialized classes inherit from this base class. For example there is a special - AiDefenseLayout which will be used to create the SamGroundObject from it. - """ - - def __init__(self, name: str, description: str = "") -> None: - self.name = name - self.description = description - self.tasks: list[GroupTask] = [] # The supported - - # All TgoGroups this layout has. - self.groups: list[TgoLayoutGroup] = [] - - # A generic layout will be used to create generic ForceGroups during the - # campaign initialization. For each generic layout a new Group will be created. - self.generic: bool = False - - def usable_by_faction(self, faction: Faction) -> bool: - # Special handling for Buildings - if ( - isinstance(self, BuildingLayout) - and self.category not in faction.building_set - ): - return False - - # Check if faction has at least 1 possible unit for non-optional groups - try: - return all( - len(group.possible_types_for_faction(faction)) > 0 - for group in self.all_unit_groups - if not group.optional - ) - except LayoutException: - return False - - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> TheaterGroundObject: - """Create the TheaterGroundObject for the TgoLayout - - This function has to be implemented by the inheriting class to create - a specific TGO like SamGroundObject or BuildingGroundObject - """ - raise NotImplementedError - - @property - def all_unit_groups(self) -> Iterator[TgoLayoutUnitGroup]: - for group in self.groups: - yield from group.unit_groups - - -class AntiAirLayout(TgoLayout): - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> IadsGroundObject: - if GroupTask.EARLY_WARNING_RADAR in self.tasks: - return EwrGroundObject(name, location, control_point) - elif any(tasking in self.tasks for tasking in GroupRole.AIR_DEFENSE.tasks): - return SamGroundObject(name, location, control_point) - raise RuntimeError( - f" No Template for AntiAir tasking ({', '.join(task.description for task in self.tasks)})" - ) - - -class BuildingLayout(TgoLayout): - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> BuildingGroundObject: - iads_role = IadsRole.for_category(self.category) - tgo_type = ( - IadsBuildingGroundObject if iads_role.participate else BuildingGroundObject - ) - return tgo_type( - name, - self.category, - location, - control_point, - self.category == "fob", - ) - - @property - def category(self) -> str: - for task in self.tasks: - if task not in [GroupTask.STRIKE_TARGET, GroupTask.OFFSHORE_STRIKE_TARGET]: - return task.description.lower() - raise RuntimeError(f"Building Template {self.name} has no building category") - - -class NavalLayout(TgoLayout): - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> TheaterGroundObject: - if GroupTask.NAVY in self.tasks: - return ShipGroundObject(name, location, control_point) - elif GroupTask.AIRCRAFT_CARRIER in self.tasks: - return CarrierGroundObject(name, location, control_point) - elif GroupTask.HELICOPTER_CARRIER in self.tasks: - return LhaGroundObject(name, location, control_point) - raise NotImplementedError - - -class DefensesLayout(TgoLayout): - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> TheaterGroundObject: - if GroupTask.MISSILE in self.tasks: - return MissileSiteGroundObject(name, location, control_point) - elif GroupTask.COASTAL in self.tasks: - return CoastalSiteGroundObject(name, location, control_point) - raise NotImplementedError - - -class GroundForceLayout(TgoLayout): - def create_ground_object( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> TheaterGroundObject: - return VehicleGroupGroundObject(name, location, control_point) diff --git a/game/layout/layoutloader.py b/game/layout/layoutloader.py deleted file mode 100644 index 6e5d626ed..000000000 --- a/game/layout/layoutloader.py +++ /dev/null @@ -1,195 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import pickle -from collections import defaultdict -from concurrent.futures import ThreadPoolExecutor -from pathlib import Path -from typing import Iterator - -import dcs -import yaml -from dcs import Point -from dcs.unitgroup import StaticGroup - -from game import persistence -from game.data.groups import GroupRole -from game.layout.layout import ( - AntiAirLayout, - BuildingLayout, - DefensesLayout, - GroundForceLayout, - LayoutUnit, - NavalLayout, - TgoLayout, - TgoLayoutGroup, - TgoLayoutUnitGroup, -) -from game.layout.layoutmapping import LayoutMapping -from game.profiling import logged_duration -from game.version import VERSION - -LAYOUT_DIR = "resources/layouts/" -LAYOUT_DUMP = "Liberation/layouts.p" - -LAYOUT_TYPES = { - GroupRole.AIR_DEFENSE: AntiAirLayout, - GroupRole.BUILDING: BuildingLayout, - GroupRole.NAVAL: NavalLayout, - GroupRole.GROUND_FORCE: GroundForceLayout, - GroupRole.DEFENSES: DefensesLayout, -} - - -class LayoutLoader: - # Map of all available layouts indexed by name - _layouts: dict[str, TgoLayout] = {} - - def __init__(self) -> None: - self._layouts = {} - - def initialize(self) -> None: - if not self._layouts: - with logged_duration("Loading layouts"): - self.load_templates() - - @property - def layouts(self) -> Iterator[TgoLayout]: - self.initialize() - yield from self._layouts.values() - - def load_templates(self) -> None: - """This will load all pre-loaded layouts from a pickle file. - If pickle can not be loaded it will import and dump the layouts""" - # We use a pickle for performance reasons. Importing takes many seconds - file = Path(persistence.base_path()) / LAYOUT_DUMP - if file.is_file(): - # Load from pickle if existing - with file.open("rb") as f: - try: - version, self._layouts = pickle.load(f) - # Check if the game version of the dump is identical to the current - if version == VERSION: - return - except Exception as e: - logging.exception(f"Error {e} reading layouts dump. Recreating.") - # If no dump is available or game version is different create a new dump - self.import_templates() - - def import_templates(self) -> None: - """This will import all layouts from the template folder - and dumps them to a pickle""" - self._layouts = {} - mappings: dict[str, list[LayoutMapping]] = defaultdict(list) - with logged_duration("Parsing mapping yamls"): - for file in Path(LAYOUT_DIR).rglob("*.yaml"): - if not file.is_file(): - raise RuntimeError(f"{file.name} is not a file") - with file.open("r", encoding="utf-8") as f: - mapping_dict = yaml.safe_load(f) - - template_map = LayoutMapping.from_dict(mapping_dict, f.name) - mappings[template_map.layout_file].append(template_map) - - with logged_duration(f"Parsing all layout miz multithreaded"): - with ThreadPoolExecutor() as exe: - exe.map(self._load_from_miz, mappings.keys(), mappings.values()) - - # Sort al the LayoutGroups with the correct index - for layout in self._layouts.values(): - layout.groups.sort(key=lambda g: g.group_index) - for group in layout.groups: - group.unit_groups.sort(key=lambda ug: ug.unit_index) - - logging.info(f"Imported {len(self._layouts)} layouts") - self._dump_templates() - - def _dump_templates(self) -> None: - file = Path(persistence.base_path()) / LAYOUT_DUMP - dump = (VERSION, self._layouts) - with file.open("wb") as fdata: - pickle.dump(dump, fdata) - - def _load_from_miz(self, miz: str, mappings: list[LayoutMapping]) -> None: - template_position: dict[str, Point] = {} - temp_mis = dcs.Mission() - with logged_duration(f"Parsing {miz}"): - # The load_file takes a lot of time to compute. That's why the layouts - # are written to a pickle and can be reloaded from the ui - # Example the whole routine: 0:00:00.934417, - # the .load_file() method: 0:00:00.920409 - temp_mis.load_file(miz) - - for mapping in mappings: - # Find the group from the mapping in any coalition - for country in itertools.chain( - temp_mis.coalition["red"].countries.values(), - temp_mis.coalition["blue"].countries.values(), - ): - for dcs_group in itertools.chain( - temp_mis.country(country.name).vehicle_group, - temp_mis.country(country.name).ship_group, - temp_mis.country(country.name).static_group, - ): - try: - g_id, u_id, group_name, group_mapping = mapping.group_for_name( - dcs_group.name - ) - except KeyError: - continue - - if not isinstance(dcs_group, StaticGroup) and max( - group_mapping.unit_count - ) > len(dcs_group.units): - logging.error( - f"Incorrect unit_count found in Layout {mapping.name}-{group_mapping.name}" - ) - - layout = self._layouts.get(mapping.name, None) - if layout is None: - # Create a new template - layout = LAYOUT_TYPES[mapping.primary_role]( - mapping.name, mapping.description - ) - layout.generic = mapping.generic - layout.tasks = mapping.tasks - self._layouts[layout.name] = layout - for i, unit in enumerate(dcs_group.units): - unit_group = None - for _unit_group in layout.all_unit_groups: - if _unit_group.name == group_mapping.name: - # We already have a layoutgroup for this dcs_group - unit_group = _unit_group - if not unit_group: - unit_group = TgoLayoutUnitGroup( - group_mapping.name, - [], - group_mapping.unit_count, - group_mapping.unit_types, - group_mapping.unit_classes, - group_mapping.fallback_classes, - u_id, - ) - unit_group.optional = group_mapping.optional - unit_group.fill = group_mapping.fill - unit_group.sub_task = group_mapping.sub_task - tgo_group = None - for _tgo_group in layout.groups: - if _tgo_group.group_name == group_name: - tgo_group = _tgo_group - if tgo_group is None: - tgo_group = TgoLayoutGroup(group_name, g_id) - layout.groups.append(tgo_group) - tgo_group.unit_groups.append(unit_group) - layout_unit = LayoutUnit.from_unit(unit) - if i == 0 and layout.name not in template_position: - template_position[layout.name] = unit.position - layout_unit.position = ( - layout_unit.position - template_position[layout.name] - ) - unit_group.layout_units.append(layout_unit) - - def by_name(self, name: str) -> TgoLayout: - self.initialize() - return self._layouts[name] diff --git a/game/layout/layoutmapping.py b/game/layout/layoutmapping.py deleted file mode 100644 index 12da9b08b..000000000 --- a/game/layout/layoutmapping.py +++ /dev/null @@ -1,138 +0,0 @@ -from __future__ import annotations -from collections import defaultdict - -from dataclasses import dataclass, field -from typing import Any, Optional, Type - -from dcs.unittype import UnitType as DcsUnitType - -from game.data.groups import GroupRole, GroupTask -from game.data.units import UnitClass -from game.dcs.helpers import unit_type_from_name - - -@dataclass -class GroupLayoutMapping: - # The group name used in the template.miz - name: str - - # Defines if the group is required for the template or can be skipped - optional: bool = False - - # Should this be filled by accessible units if optional or not - fill: bool = True - - # Allows a group to have a special SubTask (PointDefence for example) - sub_task: Optional[GroupTask] = None - - # All static units for the group - statics: list[str] = field(default_factory=list) - - # How many units should be generated from the grouplayout. If only one value is - # added this will be an exact amount. If 2 values are used it will be a random - # amount between these values. - unit_count: list[int] = field(default_factory=list) - - # All unit types the template supports. - unit_types: list[Type[DcsUnitType]] = field(default_factory=list) - - # All unit classes the template supports. - unit_classes: list[UnitClass] = field(default_factory=list) - - # Fallback Classes which are used when the unit_classes and unit_types do not fit any accessible unit from the faction. Only used for EWRs to also Use SR when no - # dedicated EWRs are available to the faction - fallback_classes: list[UnitClass] = field(default_factory=list) - - @staticmethod - def from_dict(d: dict[str, Any]) -> GroupLayoutMapping: - optional = d["optional"] if "optional" in d else False - fill = d["fill"] if "fill" in d else True - sub_task = GroupTask.by_description(d["sub_task"]) if "sub_task" in d else None - statics = d["statics"] if "statics" in d else [] - unit_count = d["unit_count"] if "unit_count" in d else [] - unit_types = [] - if "unit_types" in d: - for u in d["unit_types"]: - unit_type = unit_type_from_name(u) - if unit_type: - unit_types.append(unit_type) - unit_classes = ( - [UnitClass(u) for u in d["unit_classes"]] if "unit_classes" in d else [] - ) - fallback_classes = ( - [UnitClass(u) for u in d["fallback_classes"]] - if "fallback_classes" in d - else [] - ) - return GroupLayoutMapping( - d["name"], - optional, - fill, - sub_task, - statics, - unit_count, - unit_types, - unit_classes, - fallback_classes, - ) - - -@dataclass -class LayoutMapping: - # The name of the Template - name: str - - # An optional description to give more information about the template - description: str - - # Optional field to define if the template can be used to create generic groups - generic: bool - - # All taskings the template can be used for - tasks: list[GroupTask] - - # All Groups the template has - groups: dict[str, list[GroupLayoutMapping]] - - # Define the miz file for the template. Optional. If empty use the mapping name - layout_file: str - - @property - def primary_role(self) -> GroupRole: - return self.tasks[0].role - - @staticmethod - def from_dict(d: dict[str, Any], file_name: str) -> LayoutMapping: - groups: dict[str, list[GroupLayoutMapping]] = defaultdict(list) - for group in d["groups"]: - for group_name, group_layouts in group.items(): - groups[group_name].extend( - [ - GroupLayoutMapping.from_dict(group_layout) - for group_layout in group_layouts - ] - ) - - description = d["description"] if "description" in d else "" - generic = d["generic"] if "generic" in d else False - layout_file = ( - d["layout_file"] if "layout_file" in d else file_name.replace("yaml", "miz") - ) - tasks = [GroupTask.by_description(task) for task in d["tasks"]] - return LayoutMapping( - d["name"], - description, - generic, - tasks, - groups, - layout_file, - ) - - def group_for_name(self, name: str) -> tuple[int, int, str, GroupLayoutMapping]: - g_id = 0 - for group_name, group_mappings in self.groups.items(): - for u_id, group_mapping in enumerate(group_mappings): - if group_mapping.name == name or name in group_mapping.statics: - return g_id, u_id, group_name, group_mapping - g_id += 1 - raise KeyError diff --git a/game/logging_config.py b/game/logging_config.py deleted file mode 100644 index 19ff1c7ff..000000000 --- a/game/logging_config.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Logging APIs.""" -import logging -import logging.config -import os -from pathlib import Path - -import yaml - - -def init_logging(version: str) -> None: - """Initializes the logging configuration.""" - if not os.path.isdir("./logs"): - os.mkdir("logs") - - resources = Path("resources") - log_config = resources / "default_logging.yaml" - if (custom_log_config := resources / "logging.yaml").exists(): - log_config = custom_log_config - with log_config.open(encoding="utf-8") as log_file: - logging.config.dictConfig(yaml.safe_load(log_file)) - - logging.info(f"DCS Liberation {version}") diff --git a/game/missiongenerator/__init__.py b/game/missiongenerator/__init__.py deleted file mode 100644 index bf896fd8e..000000000 --- a/game/missiongenerator/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .missiongenerator import MissionGenerator diff --git a/game/missiongenerator/airconflictdescription.py b/game/missiongenerator/airconflictdescription.py deleted file mode 100644 index 0b82cc381..000000000 --- a/game/missiongenerator/airconflictdescription.py +++ /dev/null @@ -1,18 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - from game.theater import ConflictTheater, ControlPoint - - -class AirConflictDescription: - def __init__(self, blue_cp: ControlPoint, red_cp: ControlPoint) -> None: - self.blue_cp = blue_cp - self.red_cp = red_cp - self.center = (self.blue_cp.position + self.red_cp.position) / 2 - - @staticmethod - def for_theater(theater: ConflictTheater) -> AirConflictDescription: - player_cp, enemy_cp = theater.closest_opposing_control_points() - return AirConflictDescription(player_cp, enemy_cp) diff --git a/game/missiongenerator/aircraft/__init__.py b/game/missiongenerator/aircraft/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/missiongenerator/aircraft/aircraftbehavior.py b/game/missiongenerator/aircraft/aircraftbehavior.py deleted file mode 100644 index 6d44d3924..000000000 --- a/game/missiongenerator/aircraft/aircraftbehavior.py +++ /dev/null @@ -1,334 +0,0 @@ -import logging -from typing import Any, Optional - -from dcs.task import ( - AWACS, - AWACSTaskAction, - AntishipStrike, - CAP, - CAS, - EPLRS, - FighterSweep, - GroundAttack, - Nothing, - OptROE, - OptRTBOnBingoFuel, - OptRTBOnOutOfAmmo, - OptReactOnThreat, - OptRestrictJettison, - Refueling, - RunwayAttack, - SEAD, - Transport, - SetUnlimitedFuelCommand, -) -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight, FlightType -from game.ato.flightplans.aewc import AewcFlightPlan -from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan -from game.ato.flightplans.theaterrefueling import TheaterRefuelingFlightPlan -from game.settings import Settings - - -class AircraftBehavior: - def __init__(self, task: FlightType, settings: Settings) -> None: - self.task = task - self.settings = settings - - def apply_to(self, flight: Flight, group: FlyingGroup[Any]) -> None: - if self.task in [ - FlightType.BARCAP, - FlightType.TARCAP, - FlightType.INTERCEPTION, - ]: - self.configure_cap(group, flight) - elif self.task == FlightType.SWEEP: - self.configure_sweep(group, flight) - elif self.task == FlightType.AEWC: - self.configure_awacs(group, flight) - elif self.task == FlightType.REFUELING: - self.configure_refueling(group, flight) - elif self.task in [FlightType.CAS, FlightType.BAI]: - self.configure_cas(group, flight) - elif self.task == FlightType.DEAD: - self.configure_dead(group, flight) - elif self.task == FlightType.SEAD: - self.configure_sead(group, flight) - elif self.task == FlightType.SEAD_ESCORT: - self.configure_sead_escort(group, flight) - elif self.task == FlightType.STRIKE: - self.configure_strike(group, flight) - elif self.task == FlightType.ANTISHIP: - self.configure_anti_ship(group, flight) - elif self.task == FlightType.ESCORT: - self.configure_escort(group, flight) - elif self.task == FlightType.OCA_RUNWAY: - self.configure_runway_attack(group, flight) - elif self.task == FlightType.OCA_AIRCRAFT: - self.configure_oca_strike(group, flight) - elif self.task in [ - FlightType.TRANSPORT, - FlightType.AIR_ASSAULT, - ]: - self.configure_transport(group, flight) - elif self.task == FlightType.FERRY: - self.configure_ferry(group, flight) - else: - self.configure_unknown_task(group, flight) - - self.configure_unlimited_fuel(group, flight) - self.configure_eplrs(group, flight) - - def configure_behavior( - self, - flight: Flight, - group: FlyingGroup[Any], - react_on_threat: OptReactOnThreat.Values = OptReactOnThreat.Values.EvadeFire, - roe: Optional[int] = None, - rtb_winchester: Optional[OptRTBOnOutOfAmmo.Values] = None, - restrict_jettison: Optional[bool] = None, - mission_uses_gun: bool = True, - ) -> None: - group.points[0].tasks.clear() - group.points[0].tasks.append(OptReactOnThreat(react_on_threat)) - if roe is not None: - group.points[0].tasks.append(OptROE(roe)) - if restrict_jettison is not None: - group.points[0].tasks.append(OptRestrictJettison(restrict_jettison)) - if rtb_winchester is not None: - group.points[0].tasks.append(OptRTBOnOutOfAmmo(rtb_winchester)) - - # Confiscate the bullets of AI missions that do not rely on the gun. There is no - # "all but gun" RTB winchester option, so air to ground missions with mixed - # weapon types will insist on using all of their bullets after running out of - # missiles and bombs. Take away their bullets so they don't strafe a Tor. - # - # Exceptions are made for player flights and for airframes where the gun is - # essential like the A-10 or warbirds. - if not mission_uses_gun and not self.flight_always_keeps_gun(flight): - for unit in group.units: - unit.gun = 0 - - group.points[0].tasks.append(OptRTBOnBingoFuel(True)) - # Do not restrict afterburner. - # https://forums.eagle.ru/forum/english/digital-combat-simulator/dcs-world-2-5/bugs-and-problems-ai/ai-ad/7121294-ai-stuck-at-high-aoa-after-making-sharp-turn-if-afterburner-is-restricted - - @staticmethod - def configure_eplrs(group: FlyingGroup[Any], flight: Flight) -> None: - if flight.unit_type.eplrs_capable: - group.points[0].tasks.append(EPLRS(group.id)) - - def configure_unlimited_fuel(self, group: FlyingGroup[Any], flight: Flight) -> None: - if not flight.client_count and self.settings.ai_has_unlimited_fuel: - # This task is prepended according to the notes from the DCS changelog: - # - # NEW: Advanced Waypoint Action for Unlimited Fuel Option for AI. Please - # note the task must be at the top of Advanced Waypoint Actions list to - # make sure it works properly. - # - # https://www.digitalcombatsimulator.com/en/news/changelog/openbeta/2.9.0.46801/ - group.points[0].tasks.insert(0, SetUnlimitedFuelCommand(True)) - - def configure_cap(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = CAP.name - - if not flight.unit_type.gunfighter: - ammo_type = OptRTBOnOutOfAmmo.Values.AAM - else: - ammo_type = OptRTBOnOutOfAmmo.Values.Cannon - - self.configure_behavior(flight, group, rtb_winchester=ammo_type) - - def configure_sweep(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = FighterSweep.name - - if not flight.unit_type.gunfighter: - ammo_type = OptRTBOnOutOfAmmo.Values.AAM - else: - ammo_type = OptRTBOnOutOfAmmo.Values.Cannon - - self.configure_behavior(flight, group, rtb_winchester=ammo_type) - - def configure_cas(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = CAS.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - rtb_winchester=OptRTBOnOutOfAmmo.Values.Unguided, - restrict_jettison=True, - ) - - def configure_dead(self, group: FlyingGroup[Any], flight: Flight) -> None: - # Only CAS and SEAD are capable of the Attack Group task. SEAD is arguably more - # appropriate but it has an extremely limited list of capable aircraft, whereas - # CAS has a much wider selection of units. - # - # Note that the only effect that the DCS task type has is in determining which - # waypoint actions the group may perform. - group.task = CAS.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - rtb_winchester=OptRTBOnOutOfAmmo.Values.All, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_sead(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = SEAD.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - # ASM includes ARMs and TALDs (among other things, but those are the useful - # weapons for SEAD). - rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_strike(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = GroundAttack.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_anti_ship(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = AntishipStrike.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_runway_attack(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = RunwayAttack.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_oca_strike(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = CAS.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.OpenFire, - restrict_jettison=True, - ) - - def configure_awacs(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = AWACS.name - - if not isinstance(flight.flight_plan, AewcFlightPlan): - logging.error( - f"Cannot configure AEW&C tasks for {flight} because it does not have " - "an AEW&C flight plan." - ) - return - - # Awacs task action - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.WeaponHold, - restrict_jettison=True, - ) - - group.points[0].tasks.append(AWACSTaskAction()) - - def configure_refueling(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = Refueling.name - - if not ( - isinstance(flight.flight_plan, TheaterRefuelingFlightPlan) - or isinstance(flight.flight_plan, RecoveryTankerFlightPlan) - ): - logging.error( - f"Cannot configure racetrack refueling tasks for {flight} because it " - "does not have an racetrack refueling flight plan." - ) - return - - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.WeaponHold, - restrict_jettison=True, - ) - - def configure_escort(self, group: FlyingGroup[Any], flight: Flight) -> None: - # Escort groups are actually given the CAP task so they can perform the - # Search Then Engage task, which we have to use instead of the Escort - # task for the reasons explained in JoinPointBuilder. - group.task = CAP.name - self.configure_behavior( - flight, group, roe=OptROE.Values.OpenFire, restrict_jettison=True - ) - - def configure_sead_escort(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = SEAD.name - self.configure_behavior( - flight, - group, - roe=OptROE.Values.OpenFire, - # ASM includes ARMs and TALDs (among other things, but those are the useful - # weapons for SEAD). - rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM, - restrict_jettison=True, - mission_uses_gun=False, - ) - - def configure_transport(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = Transport.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.WeaponHold, - restrict_jettison=True, - ) - - def configure_ferry(self, group: FlyingGroup[Any], flight: Flight) -> None: - group.task = Nothing.name - self.configure_behavior( - flight, - group, - react_on_threat=OptReactOnThreat.Values.EvadeFire, - roe=OptROE.Values.WeaponHold, - restrict_jettison=True, - ) - - def configure_unknown_task(self, group: FlyingGroup[Any], flight: Flight) -> None: - logging.error(f"Unhandled flight type: {flight.flight_type}") - self.configure_behavior(flight, group) - - @staticmethod - def flight_always_keeps_gun(flight: Flight) -> bool: - # Never take bullets from players. They're smart enough to know when to use it - # and when to RTB. - if flight.client_count > 0: - return True - - return flight.unit_type.always_keeps_gun diff --git a/game/missiongenerator/aircraft/aircraftgenerator.py b/game/missiongenerator/aircraft/aircraftgenerator.py deleted file mode 100644 index 8c13589e9..000000000 --- a/game/missiongenerator/aircraft/aircraftgenerator.py +++ /dev/null @@ -1,192 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime -from functools import cached_property -from typing import Any, Dict, TYPE_CHECKING - -from dcs.country import Country -from dcs.mission import Mission -from dcs.terrain.terrain import NoParkingSlotError -from dcs.unitgroup import FlyingGroup, StaticGroup - -from game.ato.airtaaskingorder import AirTaskingOrder -from game.ato.flight import Flight -from game.ato.flightstate import Completed -from game.ato.flighttype import FlightType -from game.ato.package import Package -from game.ato.starttype import StartType -from game.factions.faction import Faction -from game.missiongenerator.missiondata import MissionData -from game.radio.radios import RadioRegistry -from game.radio.tacan import TacanRegistry -from game.runways import RunwayData -from game.settings import Settings -from game.theater.controlpoint import ( - Airfield, - ControlPoint, - Fob, -) -from game.unitmap import UnitMap -from .aircraftpainter import AircraftPainter -from .flightdata import FlightData -from .flightgroupconfigurator import FlightGroupConfigurator -from .flightgroupspawner import FlightGroupSpawner - -if TYPE_CHECKING: - from game import Game - from game.squadrons import Squadron - - -class AircraftGenerator: - def __init__( - self, - mission: Mission, - settings: Settings, - game: Game, - time: datetime, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - unit_map: UnitMap, - mission_data: MissionData, - helipads: dict[ControlPoint, StaticGroup], - ) -> None: - self.mission = mission - self.settings = settings - self.game = game - self.time = time - self.radio_registry = radio_registry - self.tacan_registy = tacan_registry - self.unit_map = unit_map - # A list of per-package briefing data, which is in turn a list of per-flight - # briefing data. - self.briefing_data: list[list[FlightData]] = [] - self.mission_data = mission_data - self.helipads = helipads - - @cached_property - def use_client(self) -> bool: - """True if Client should be used instead of Player.""" - blue_clients = self.client_slots_in_ato(self.game.blue.ato) - red_clients = self.client_slots_in_ato(self.game.red.ato) - return blue_clients + red_clients > 1 - - @staticmethod - def client_slots_in_ato(ato: AirTaskingOrder) -> int: - total = 0 - for package in ato.packages: - for flight in package.flights: - total += flight.client_count - return total - - def clear_parking_slots(self) -> None: - for cp in self.game.theater.controlpoints: - for parking_slot in cp.parking_slots: - parking_slot.unit_id = None - - def generate_flights( - self, - country: Country, - ato: AirTaskingOrder, - dynamic_runways: Dict[str, RunwayData], - ) -> None: - """Adds aircraft to the mission for every flight in the ATO. - - Aircraft generation is done by walking the ATO and spawning each flight in turn. - After the flight is generated the group is added to the UnitMap so aircraft - deaths can be tracked. - - Args: - country: The country from the mission to use for this ATO. - ato: The ATO to spawn aircraft for. - dynamic_runways: Runway data for carriers and FARPs. - """ - for package in ato.packages: - if not package.flights: - continue - package_briefing_data: list[FlightData] = [] - for flight in package.flights: - if flight.alive: - logging.info(f"Generating flight: {flight.unit_type}") - group, briefing_data = self.create_and_configure_flight( - flight, country, dynamic_runways - ) - package_briefing_data.append(briefing_data) - self.unit_map.add_aircraft(group, flight) - self.briefing_data.append(package_briefing_data) - - def spawn_unused_aircraft( - self, player_country: Country, enemy_country: Country - ) -> None: - for control_point in self.game.theater.controlpoints: - if not isinstance(control_point, Airfield): - continue - - faction = self.game.coalition_for(control_point.captured).faction - if control_point.captured: - country = player_country - else: - country = enemy_country - - for squadron in control_point.squadrons: - try: - self._spawn_unused_for(squadron, country, faction) - except NoParkingSlotError: - # If we run out of parking, stop spawning aircraft at this base. - break - - def _spawn_unused_for( - self, squadron: Squadron, country: Country, faction: Faction - ) -> None: - assert isinstance(squadron.location, Airfield) - for _ in range(squadron.untasked_aircraft): - # Creating a flight even those this isn't a fragged mission lets us - # reuse the existing debriefing code. - # TODO: Special flight type? - flight = Flight( - Package(squadron.location, self.game.db.flights), - faction.country, - squadron, - 1, - FlightType.BARCAP, - StartType.COLD, - divert=None, - ) - flight.state = Completed(flight, self.game.settings) - - group = FlightGroupSpawner( - flight, country, self.mission, self.helipads - ).create_idle_aircraft() - AircraftPainter(flight, group).apply_livery() - self.unit_map.add_aircraft(group, flight) - - def create_and_configure_flight( - self, flight: Flight, country: Country, dynamic_runways: Dict[str, RunwayData] - ) -> tuple[FlyingGroup[Any], FlightData]: - """Creates and configures the flight group in the mission.""" - group = FlightGroupSpawner( - flight, country, self.mission, self.helipads - ).create_flight_group() - - briefing_data = FlightGroupConfigurator( - flight, - group, - self.game, - self.mission, - self.time, - self.radio_registry, - self.tacan_registy, - self.mission_data, - dynamic_runways, - self.use_client, - self.unit_map, - ).configure() - - wpt = group.waypoint("LANDING") - if flight.is_helo and isinstance(flight.arrival, Fob) and wpt: - hpad = self.helipads[flight.arrival].units.pop(0) - wpt.helipad_id = hpad.id - wpt.link_unit = hpad.id - self.helipads[flight.arrival].units.append(hpad) - - return group, briefing_data diff --git a/game/missiongenerator/aircraft/aircraftpainter.py b/game/missiongenerator/aircraft/aircraftpainter.py deleted file mode 100644 index df45ccaf6..000000000 --- a/game/missiongenerator/aircraft/aircraftpainter.py +++ /dev/null @@ -1,44 +0,0 @@ -from __future__ import annotations - -import random -from typing import Any, Optional - -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight - - -class AircraftPainter: - def __init__(self, flight: Flight, group: FlyingGroup[Any]) -> None: - self.flight = flight - self.group = group - - def livery_from_unit_type(self) -> Optional[str]: - return self.flight.unit_type.default_livery - - def livery_from_faction(self) -> Optional[str]: - faction = self.flight.squadron.coalition.faction - if ( - choices := faction.liveries_overrides.get(self.flight.unit_type) - ) is not None: - return random.choice(choices) - return None - - def livery_from_squadron(self) -> Optional[str]: - return self.flight.squadron.livery - - def determine_livery(self) -> Optional[str]: - if (livery := self.livery_from_squadron()) is not None: - return livery - if (livery := self.livery_from_faction()) is not None: - return livery - if (livery := self.livery_from_unit_type()) is not None: - return livery - return None - - def apply_livery(self) -> None: - livery = self.determine_livery() - if livery is None: - return - for unit in self.group.units: - unit.livery_id = livery diff --git a/game/missiongenerator/aircraft/bingoestimator.py b/game/missiongenerator/aircraft/bingoestimator.py deleted file mode 100644 index a5abee110..000000000 --- a/game/missiongenerator/aircraft/bingoestimator.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -import math -from typing import TYPE_CHECKING - -from dcs import Point - -from game.utils import Distance, meters - -if TYPE_CHECKING: - from game.ato.flightwaypoint import FlightWaypoint - from game.dcs.aircrafttype import FuelConsumption - - -class BingoEstimator: - """Estimates bingo/joker fuel values for a flight plan. - - The results returned by this class are bogus for most airframes. Only the few - airframes which have fuel consumption data available can provide even moderately - reliable estimates. **Do not use this for flight planning.** This should only be - used in briefing context where it's okay to be wrong. - """ - - def __init__( - self, - fuel_consumption: FuelConsumption | None, - arrival: Point, - divert: Point | None, - waypoints: list[FlightWaypoint], - ) -> None: - self.fuel_consumption = fuel_consumption - self.arrival = arrival - self.divert = divert - self.waypoints = waypoints - - def estimate_bingo(self) -> int: - """Bingo fuel value for the FlightPlan""" - if (fuel := self.fuel_consumption) is not None: - return self._fuel_consumption_based_estimate(fuel) - return self._legacy_bingo_estimate() - - def estimate_joker(self) -> int: - """Joker fuel value for the FlightPlan""" - return self.estimate_bingo() + 1000 - - def _fuel_consumption_based_estimate(self, fuel: FuelConsumption) -> int: - distance_to_arrival = self._max_distance_from(self.arrival) - fuel_consumed = fuel.cruise * distance_to_arrival.nautical_miles - bingo = fuel_consumed + fuel.min_safe - return math.ceil(bingo / 100) * 100 - - def _legacy_bingo_estimate(self) -> int: - distance_to_arrival = self._max_distance_from(self.arrival) - - bingo = 1000.0 # Minimum Emergency Fuel - bingo += 500 # Visual Traffic - bingo += 15 * distance_to_arrival.nautical_miles - - if self.divert is not None: - max_divert_distance = self._max_distance_from(self.divert) - bingo += 10 * max_divert_distance.nautical_miles - - return round(bingo / 100) * 100 - - def _max_distance_from(self, point: Point) -> Distance: - return max(meters(point.distance_to_point(w.position)) for w in self.waypoints) diff --git a/game/missiongenerator/aircraft/flightdata.py b/game/missiongenerator/aircraft/flightdata.py deleted file mode 100644 index 6d55813ea..000000000 --- a/game/missiongenerator/aircraft/flightdata.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from datetime import timedelta -from typing import Optional, TYPE_CHECKING - -from dcs.flyingunit import FlyingUnit - -from game.callsigns import create_group_callsign_from_unit - -if TYPE_CHECKING: - from game.ato import FlightType, FlightWaypoint, Package - from game.dcs.aircrafttype import AircraftType - from game.radio.radios import RadioFrequency - from game.runways import RunwayData - - -@dataclass(frozen=True) -class ChannelAssignment: - radio_id: int - channel: int - - -@dataclass -class FlightData: - """Details of a planned flight.""" - - #: The package that the flight belongs to. - package: Package - - flight_type: FlightType - - aircraft_type: AircraftType - - #: All units in the flight. - units: list[FlyingUnit] - - #: Total number of aircraft in the flight. - size: int - - #: True if this flight belongs to the player's coalition. - friendly: bool - - #: Number of seconds after mission start the flight is set to depart. - departure_delay: timedelta - - #: Arrival airport. - arrival: RunwayData - - #: Departure airport. - departure: RunwayData - - #: Diver airport. - divert: Optional[RunwayData] - - #: Waypoints of the flight plan. - waypoints: list[FlightWaypoint] - - #: Radio frequency for intra-flight communications. - intra_flight_channel: RadioFrequency - - #: Bingo fuel value in lbs. - bingo_fuel: Optional[int] - - joker_fuel: Optional[int] - - laser_codes: list[Optional[int]] - - custom_name: Optional[str] - - callsign: str = field(init=False) - - #: Map of radio frequencies to their assigned radio and channel, if any. - frequency_to_channel_map: dict[RadioFrequency, ChannelAssignment] = field( - init=False, default_factory=dict - ) - - def __post_init__(self) -> None: - self.callsign = create_group_callsign_from_unit(self.units[0]) - - @property - def client_units(self) -> list[FlyingUnit]: - """List of playable units in the flight.""" - return [u for u in self.units if u.is_human()] - - def num_radio_channels(self, radio_id: int) -> int: - """Returns the number of preset channels for the given radio.""" - # Note: pydcs only initializes the radio presets for client slots. - return self.client_units[0].num_radio_channels(radio_id) - - def channel_for(self, frequency: RadioFrequency) -> Optional[ChannelAssignment]: - """Returns the radio and channel number for the given frequency.""" - return self.frequency_to_channel_map.get(frequency, None) - - def assign_channel( - self, radio_id: int, channel_id: int, frequency: RadioFrequency - ) -> None: - """Assigns a preset radio channel to the given frequency.""" - for unit in self.client_units: - unit.set_radio_channel_preset(radio_id, channel_id, frequency.mhz) - - # One frequency could be bound to multiple channels. Prefer the first, - # since with the current implementation it will be the lowest numbered - # channel. - if frequency not in self.frequency_to_channel_map: - self.frequency_to_channel_map[frequency] = ChannelAssignment( - radio_id, channel_id - ) diff --git a/game/missiongenerator/aircraft/flightgroupconfigurator.py b/game/missiongenerator/aircraft/flightgroupconfigurator.py deleted file mode 100644 index 11bc26ad5..000000000 --- a/game/missiongenerator/aircraft/flightgroupconfigurator.py +++ /dev/null @@ -1,271 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime -from typing import Any, Optional, TYPE_CHECKING - -from dcs import Mission, Point -from dcs.flyingunit import FlyingUnit -from dcs.unit import Skill -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight, FlightType -from game.callsigns import callsign_for_support_unit -from game.data.weapons import Pylon -from game.missiongenerator.logisticsgenerator import LogisticsGenerator -from game.missiongenerator.missiondata import AwacsInfo, MissionData, TankerInfo -from game.radio.radios import RadioFrequency, RadioRegistry -from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage -from game.runways import RunwayData -from game.squadrons import Pilot -from game.unitmap import UnitMap -from .aircraftbehavior import AircraftBehavior -from .aircraftpainter import AircraftPainter -from .bingoestimator import BingoEstimator -from .flightdata import FlightData -from .waypoints import WaypointGenerator -from ...ato.flightmember import FlightMember - -if TYPE_CHECKING: - from game import Game - - -class FlightGroupConfigurator: - def __init__( - self, - flight: Flight, - group: FlyingGroup[Any], - game: Game, - mission: Mission, - time: datetime, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - mission_data: MissionData, - dynamic_runways: dict[str, RunwayData], - use_client: bool, - unit_map: UnitMap, - ) -> None: - self.flight = flight - self.group = group - self.game = game - self.mission = mission - self.time = time - self.radio_registry = radio_registry - self.tacan_registry = tacan_registry - self.mission_data = mission_data - self.dynamic_runways = dynamic_runways - self.use_client = use_client - self.unit_map = unit_map - - def configure(self) -> FlightData: - AircraftBehavior(self.flight.flight_type, self.game.settings).apply_to( - self.flight, self.group - ) - AircraftPainter(self.flight, self.group).apply_livery() - self.setup_props() - self.setup_payloads() - self.setup_fuel() - flight_channel = self.setup_radios() - - laser_codes: list[Optional[int]] = [] - for unit, member in zip(self.group.units, self.flight.iter_members()): - self.configure_flight_member(unit, member, laser_codes) - - divert = None - if self.flight.divert is not None: - divert = self.flight.divert.active_runway( - self.game.theater, self.game.conditions, self.dynamic_runways - ) - - if self.flight.flight_type in [ - FlightType.TRANSPORT, - FlightType.AIR_ASSAULT, - ] and self.game.lua_plugin_manager.is_plugin_enabled("ctld"): - transfer = None - if self.flight.flight_type == FlightType.TRANSPORT: - coalition = self.game.coalition_for(player=self.flight.blue) - transfer = coalition.transfers.transfer_for_flight(self.flight) - self.mission_data.logistics.append( - LogisticsGenerator( - self.flight, - self.group, - self.mission, - self.game.lua_plugin_manager, - transfer, - ).generate_logistics() - ) - - mission_start_time, waypoints = WaypointGenerator( - self.flight, - self.group, - self.mission, - self.time, - self.game.settings, - self.mission_data, - self.unit_map, - ).create_waypoints() - - divert_position: Point | None = None - if self.flight.divert is not None: - divert_position = self.flight.divert.position - bingo_estimator = BingoEstimator( - self.flight.unit_type.fuel_consumption, - self.flight.arrival.position, - divert_position, - self.flight.flight_plan.waypoints, - ) - - return FlightData( - package=self.flight.package, - aircraft_type=self.flight.unit_type, - flight_type=self.flight.flight_type, - units=self.group.units, - size=len(self.group.units), - friendly=self.flight.departure.captured, - departure_delay=mission_start_time, - departure=self.flight.departure.active_runway( - self.game.theater, self.game.conditions, self.dynamic_runways - ), - arrival=self.flight.arrival.active_runway( - self.game.theater, self.game.conditions, self.dynamic_runways - ), - divert=divert, - waypoints=waypoints, - intra_flight_channel=flight_channel, - bingo_fuel=bingo_estimator.estimate_bingo(), - joker_fuel=bingo_estimator.estimate_joker(), - custom_name=self.flight.custom_name, - laser_codes=laser_codes, - ) - - def configure_flight_member( - self, unit: FlyingUnit, member: FlightMember, laser_codes: list[Optional[int]] - ) -> None: - self.set_skill(unit, member) - if (code := member.tgp_laser_code) is not None: - laser_codes.append(code.code) - else: - laser_codes.append(None) - - def setup_radios(self) -> RadioFrequency: - if self.flight.flight_type in {FlightType.AEWC, FlightType.REFUELING}: - channel = self.radio_registry.alloc_uhf() - self.register_air_support(channel) - else: - channel = self.flight.unit_type.alloc_flight_radio(self.radio_registry) - - self.group.set_frequency(channel.mhz) - return channel - - def register_air_support(self, channel: RadioFrequency) -> None: - callsign = callsign_for_support_unit(self.group) - if self.flight.flight_type is FlightType.AEWC: - self.mission_data.awacs.append( - AwacsInfo( - group_name=str(self.group.name), - callsign=callsign, - freq=channel, - depature_location=self.flight.departure.name, - end_time=self.flight.flight_plan.mission_departure_time, - start_time=self.flight.flight_plan.takeoff_time(), - blue=self.flight.departure.captured, - ) - ) - elif self.flight.flight_type is FlightType.REFUELING: - tacan = self.tacan_registry.alloc_for_band(TacanBand.Y, TacanUsage.AirToAir) - self.mission_data.tankers.append( - TankerInfo( - group_name=str(self.group.name), - callsign=callsign, - variant=self.flight.unit_type.display_name, - freq=channel, - tacan=tacan, - start_time=self.flight.flight_plan.mission_begin_on_station_time, - end_time=self.flight.flight_plan.mission_departure_time, - blue=self.flight.departure.captured, - ) - ) - - def set_skill(self, unit: FlyingUnit, member: FlightMember) -> None: - if not member.is_player: - unit.skill = self.skill_level_for(unit, member.pilot) - return - - if self.use_client: - unit.set_client() - else: - unit.set_player() - - def skill_level_for(self, unit: FlyingUnit, pilot: Optional[Pilot]) -> Skill: - if self.flight.squadron.player: - base_skill = Skill(self.game.settings.player_skill) - else: - base_skill = Skill(self.game.settings.enemy_skill) - - if pilot is None: - logging.error(f"Cannot determine skill level: {unit.name} has not pilot") - return base_skill - - levels = [ - Skill.Average, - Skill.Good, - Skill.High, - Skill.Excellent, - ] - current_level = levels.index(base_skill) - missions_for_skill_increase = 4 - increase = pilot.record.missions_flown // missions_for_skill_increase - capped_increase = min(current_level + increase, len(levels) - 1) - - if self.game.settings.ai_pilot_levelling: - new_level = capped_increase - else: - new_level = current_level - - return levels[new_level] - - def setup_props(self) -> None: - for unit, member in zip(self.group.units, self.flight.iter_members()): - props = dict(member.properties) - if (code := member.weapon_laser_code) is not None: - for laser_code_config in self.flight.unit_type.laser_code_configs: - props.update(laser_code_config.property_dict_for_code(code.code)) - for prop_id, value in props.items(): - unit.set_property(prop_id, value) - - def setup_payloads(self) -> None: - for unit, member in zip(self.group.units, self.flight.iter_members()): - self.setup_payload(unit, member) - - def setup_payload(self, unit: FlyingUnit, member: FlightMember) -> None: - unit.pylons.clear() - - loadout = member.loadout - if self.game.settings.restrict_weapons_by_date: - loadout = loadout.degrade_for_date(self.flight.unit_type, self.game.date) - - for pylon_number, weapon in loadout.pylons.items(): - if weapon is None: - continue - pylon = Pylon.for_aircraft(self.flight.unit_type, pylon_number) - pylon.equip(unit, weapon) - - def setup_fuel(self) -> None: - fuel = self.flight.state.estimate_fuel() - if fuel < 0: - logging.warning( - f"Flight {self.flight} is estimated to have no fuel at mission start. " - "This estimate does not account for external fuel tanks. Setting " - "starting fuel to 100kg." - ) - fuel = 100 - for unit, pilot in zip(self.group.units, self.flight.roster.iter_pilots()): - if pilot is not None and pilot.player: - unit.fuel = fuel - elif (max_takeoff_fuel := self.flight.max_takeoff_fuel()) is not None: - unit.fuel = max_takeoff_fuel - else: - # pydcs arbitrarily reduces the fuel of in-flight spawns by 10%. We do - # our own tracking, so undo that. - # https://github.com/pydcs/dcs/commit/303a81a8e0c778599fe136dd22cb2ae8123639a6 - unit.fuel = self.flight.unit_type.dcs_unit_type.fuel_max diff --git a/game/missiongenerator/aircraft/flightgroupspawner.py b/game/missiongenerator/aircraft/flightgroupspawner.py deleted file mode 100644 index b8a51b827..000000000 --- a/game/missiongenerator/aircraft/flightgroupspawner.py +++ /dev/null @@ -1,277 +0,0 @@ -import logging -import random -from typing import Any, Union - -from dcs import Mission -from dcs.country import Country -from dcs.mapping import Vector2 -from dcs.mission import StartType as DcsStartType -from dcs.planes import Su_33 -from dcs.ships import KUZNECOW -from dcs.terrain import Airport, NoParkingSlotError -from dcs.unitgroup import FlyingGroup, ShipGroup, StaticGroup - -from game.ato import Flight -from game.ato.flightstate import InFlight -from game.ato.starttype import StartType -from game.ato.traveltime import GroundSpeed -from game.naming import namegen -from game.theater import Airfield, ControlPoint, Fob, NavalControlPoint, OffMapSpawn -from game.utils import feet, meters - -WARM_START_HELI_ALT = meters(500) -WARM_START_ALTITUDE = meters(3000) - -# In-flight spawns are MSL for the first waypoint (this can maybe be changed to AGL, but -# AGL waypoints have different piloting behavior, so we need to check whether that's -# safe to do first), so spawn them high enough that they're unlikely to be near (or -# under) the ground, or any nearby obstacles. The highest airfield in DCS is Kerman in -# PG at 5700ft. This could still be too low if there are tall obstacles near the -# airfield, but the lowest we can push this the better to avoid spawning helicopters -# well above the altitude for WP1. -MINIMUM_MID_MISSION_SPAWN_ALTITUDE_MSL = feet(6000) -MINIMUM_MID_MISSION_SPAWN_ALTITUDE_AGL = feet(500) - -RTB_ALTITUDE = meters(800) -RTB_DISTANCE = 5000 -HELI_ALT = 500 - - -class FlightGroupSpawner: - def __init__( - self, - flight: Flight, - country: Country, - mission: Mission, - helipads: dict[ControlPoint, StaticGroup], - ) -> None: - self.flight = flight - self.country = country - self.mission = mission - self.helipads = helipads - - def create_flight_group(self) -> FlyingGroup[Any]: - """Creates the group for the flight and adds it to the mission. - - Each flight is spawned according to its FlightState at the time of mission - generation. Aircraft that are WaitingForStart will be set up based on their - StartType with a delay. Note that delays are actually created during waypoint - generation. - - Aircraft that are *not* WaitingForStart will be spawned in their current state. - We cannot spawn aircraft mid-taxi, so when the simulated state is near the end - of a long taxi period the aircraft will be spawned in their parking spot. This - could lead to problems but that's what loiter points are for. The other pre- - flight states have the same problem but are much shorter and more easily covered - by the loiter time. Player flights that are spawned near the end of their cold - start have the biggest problem but players are able to cut corners to make up - for lost time. - - Aircraft that are already in the air will be spawned at their estimated - location, speed, and altitude based on their flight plan. - """ - if ( - self.flight.state.is_waiting_for_start - or self.flight.state.spawn_type is not StartType.IN_FLIGHT - ): - return self.generate_flight_at_departure() - return self.generate_mid_mission() - - def create_idle_aircraft(self) -> FlyingGroup[Any]: - airport = self.flight.squadron.location.dcs_airport - assert airport is not None - group = self._generate_at_airport( - name=namegen.next_aircraft_name(self.country, self.flight), - airport=airport, - ) - - group.uncontrolled = True - return group - - @property - def start_type(self) -> StartType: - return self.flight.state.spawn_type - - def generate_flight_at_departure(self) -> FlyingGroup[Any]: - name = namegen.next_aircraft_name(self.country, self.flight) - cp = self.flight.departure - try: - if self.start_type is StartType.IN_FLIGHT: - group = self._generate_over_departure(name, cp) - return group - elif isinstance(cp, NavalControlPoint): - group_name = cp.get_carrier_group_name() - carrier_group = self.mission.find_group(group_name) - if not isinstance(carrier_group, ShipGroup): - raise RuntimeError( - f"Carrier group {carrier_group} is a " - f"{carrier_group.__class__.__name__}, expected a ShipGroup" - ) - return self._generate_at_group(name, carrier_group) - elif isinstance(cp, Fob): - if not self.flight.unit_type.helicopter: - raise RuntimeError( - f"Cannot spawn fixed-wing aircraft at {cp} because it is a FOB" - ) - return self._generate_at_cp_helipad(name, cp) - elif isinstance(cp, Airfield): - return self._generate_at_airport(name, cp.airport) - else: - raise NotImplementedError( - f"Aircraft spawn behavior not implemented for {cp} ({cp.__class__})" - ) - except NoParkingSlotError: - # Generated when there is no place on Runway or on Parking Slots - logging.warning( - "No room on runway or parking slots. Starting from the air." - ) - group = self._generate_over_departure(name, cp) - group.points[0].alt = 1500 - return group - - def generate_mid_mission(self) -> FlyingGroup[Any]: - assert isinstance(self.flight.state, InFlight) - name = namegen.next_aircraft_name(self.country, self.flight) - speed = self.flight.state.estimate_speed() - pos = self.flight.state.estimate_position() - pos += Vector2(random.randint(100, 1000), random.randint(100, 1000)) - alt, alt_type = self.flight.state.estimate_altitude() - - # We don't know where the ground is, so just make sure that any aircraft - # spawning at an MSL altitude is spawned at some minimum altitude. - # https://github.com/dcs-liberation/dcs_liberation/issues/1941 - if alt_type == "BARO" and alt < MINIMUM_MID_MISSION_SPAWN_ALTITUDE_MSL: - alt = MINIMUM_MID_MISSION_SPAWN_ALTITUDE_MSL - - # Set a minimum AGL value for 'alt' if needed, - # otherwise planes might crash in trees and stuff. - if alt_type == "RADIO" and alt < MINIMUM_MID_MISSION_SPAWN_ALTITUDE_AGL: - alt = MINIMUM_MID_MISSION_SPAWN_ALTITUDE_AGL - - group = self.mission.flight_group( - country=self.country, - name=name, - aircraft_type=self.flight.unit_type.dcs_unit_type, - airport=None, - position=pos, - altitude=alt.meters, - speed=speed.kph, - maintask=None, - group_size=self.flight.count, - ) - - group.points[0].alt_type = alt_type - # We don't need to add waypoint tasks for the starting waypoint here because we - # do that in WaypointGenerator. - return group - - def _generate_at_airport(self, name: str, airport: Airport) -> FlyingGroup[Any]: - # TODO: Delayed runway starts should be converted to air starts for multiplayer. - # Runway starts do not work with late activated aircraft in multiplayer. Instead - # of spawning on the runway the aircraft will spawn on the taxiway, potentially - # somewhere that they don't fit anyway. We should either upgrade these to air - # starts or (less likely) downgrade to warm starts to avoid the issue when the - # player is generating the mission for multiplayer (which would need a new - # option). - return self.mission.flight_group_from_airport( - country=self.country, - name=name, - aircraft_type=self.flight.unit_type.dcs_unit_type, - airport=airport, - maintask=None, - start_type=self.dcs_start_type(), - group_size=self.flight.count, - parking_slots=None, - ) - - def _generate_over_departure( - self, name: str, origin: ControlPoint - ) -> FlyingGroup[Any]: - at = origin.position - - alt_type = "RADIO" - if isinstance(origin, OffMapSpawn): - alt = self.flight.flight_plan.waypoints[0].alt - alt_type = self.flight.flight_plan.waypoints[0].alt_type - elif self.flight.unit_type.helicopter: - alt = WARM_START_HELI_ALT - else: - alt = WARM_START_ALTITUDE - - speed = GroundSpeed.for_flight(self.flight, alt) - pos = at + Vector2(random.randint(100, 1000), random.randint(100, 1000)) - - group = self.mission.flight_group( - country=self.country, - name=name, - aircraft_type=self.flight.unit_type.dcs_unit_type, - airport=None, - position=pos, - altitude=alt.meters, - speed=speed.kph, - maintask=None, - group_size=self.flight.count, - ) - - group.points[0].alt_type = alt_type - return group - - def _generate_at_group( - self, name: str, at: Union[ShipGroup, StaticGroup] - ) -> FlyingGroup[Any]: - return self.mission.flight_group_from_unit( - country=self.country, - name=name, - aircraft_type=self.flight.unit_type.dcs_unit_type, - pad_group=at, - maintask=None, - start_type=self._start_type_at_group(at), - group_size=self.flight.count, - ) - - def _generate_at_cp_helipad(self, name: str, cp: ControlPoint) -> FlyingGroup[Any]: - try: - helipad = self.helipads[cp] - except IndexError: - raise NoParkingSlotError() - - group = self._generate_at_group(name, helipad) - - if self.start_type is StartType.WARM: - group.points[0].type = "TakeOffParkingHot" - hpad = helipad.units[0] - for i in range(self.flight.count): - group.units[i].position = hpad.position - group.units[i].heading = hpad.heading - # pydcs has just `parking_id = None`, so mypy thinks str is invalid. Ought - # to fix pydcs, but that's not the kind of change we want to pull into the - # 6.1 branch, and frankly we should probably just improve pydcs's handling - # of FARPs instead. - group.units[i].parking_id = str(i + 1) # type: ignore - return group - - def dcs_start_type(self) -> DcsStartType: - if self.start_type is StartType.RUNWAY: - return DcsStartType.Runway - elif self.start_type is StartType.COLD: - return DcsStartType.Cold - elif self.start_type is StartType.WARM: - return DcsStartType.Warm - raise ValueError(f"There is no pydcs StartType matching {self.start_type}") - - def _start_type_at_group( - self, - at: Union[ShipGroup, StaticGroup], - ) -> DcsStartType: - group_units = at.units - # Setting Su-33s starting from the non-supercarrier Kuznetsov to take off from - # runway to work around a DCS AI issue preventing Su-33s from taking off when - # set to "Takeoff from ramp" (#1352) - if ( - self.flight.unit_type.dcs_unit_type == Su_33 - and group_units[0] is not None - and group_units[0].type == KUZNECOW.id - ): - return DcsStartType.Runway - else: - return self.dcs_start_type() diff --git a/game/missiongenerator/aircraft/waypoints/__init__.py b/game/missiongenerator/aircraft/waypoints/__init__.py deleted file mode 100644 index b21f9cbfd..000000000 --- a/game/missiongenerator/aircraft/waypoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .waypointgenerator import WaypointGenerator diff --git a/game/missiongenerator/aircraft/waypoints/antishipingress.py b/game/missiongenerator/aircraft/waypoints/antishipingress.py deleted file mode 100644 index 1cead40eb..000000000 --- a/game/missiongenerator/aircraft/waypoints/antishipingress.py +++ /dev/null @@ -1,45 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import AttackGroup, OptFormation, WeaponType - -from game.theater import NavalControlPoint, TheaterGroundObject -from game.transfers import MultiGroupTransport -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class AntiShipIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - # TODO: Add common "UnitGroupTarget" base type. - group_names = [] - target = self.package.target - if isinstance(target, TheaterGroundObject): - for group in target.groups: - group_names.append(group.group_name) - elif isinstance(target, MultiGroupTransport): - group_names.append(target.name) - elif isinstance(target, NavalControlPoint): - carrier_name = target.get_carrier_group_name() - if carrier_name: - group_names.append(carrier_name) - else: - logging.error( - "Unexpected target type for anti-ship mission: %s", - target.__class__.__name__, - ) - return - - for group_name in group_names: - miz_group = self.mission.find_group(group_name) - if miz_group is None: - logging.error( - "Could not find group for anti-ship mission %s", group_name - ) - continue - - task = AttackGroup( - miz_group.id, weapon_type=WeaponType.Auto, group_attack=True - ) - waypoint.tasks.append(task) - - waypoint.tasks.append(OptFormation.trail_open()) diff --git a/game/missiongenerator/aircraft/waypoints/baiingress.py b/game/missiongenerator/aircraft/waypoints/baiingress.py deleted file mode 100644 index 2b86d0b4f..000000000 --- a/game/missiongenerator/aircraft/waypoints/baiingress.py +++ /dev/null @@ -1,41 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import AttackGroup, OptFormation, WeaponType - -from game.theater import NavalControlPoint, TheaterGroundObject -from game.transfers import MultiGroupTransport -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class BaiIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - # TODO: Add common "UnitGroupTarget" base type. - group_names = [] - target = self.package.target - if isinstance(target, TheaterGroundObject): - for group in target.groups: - group_names.append(group.group_name) - elif isinstance(target, MultiGroupTransport): - group_names.append(target.name) - elif isinstance(target, NavalControlPoint): - carrier_name = target.get_carrier_group_name() - if carrier_name: - group_names.append(carrier_name) - else: - logging.error( - "Unexpected target type for BAI mission: %s", - target.__class__.__name__, - ) - return - - for group_name in group_names: - miz_group = self.mission.find_group(group_name) - if miz_group is None: - logging.error("Could not find group for BAI mission %s", group_name) - continue - - task = AttackGroup(miz_group.id, weapon_type=WeaponType.Auto) - waypoint.tasks.append(task) - - waypoint.tasks.append(OptFormation.trail_open()) diff --git a/game/missiongenerator/aircraft/waypoints/cargostop.py b/game/missiongenerator/aircraft/waypoints/cargostop.py deleted file mode 100644 index f8aa06efe..000000000 --- a/game/missiongenerator/aircraft/waypoints/cargostop.py +++ /dev/null @@ -1,14 +0,0 @@ -from dcs.point import MovingPoint, PointAction - -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class CargoStopBuilder(PydcsWaypointBuilder): - def build(self) -> MovingPoint: - waypoint = super().build() - waypoint.type = "LandingReFuAr" - waypoint.action = PointAction.LandingReFuAr - waypoint.landing_refuel_rearm_time = 2 # Minutes. - if (control_point := self.waypoint.control_point) is not None: - waypoint.airdrome_id = control_point.airdrome_id_for_landing - return waypoint diff --git a/game/missiongenerator/aircraft/waypoints/casingress.py b/game/missiongenerator/aircraft/waypoints/casingress.py deleted file mode 100644 index fc39b8c8a..000000000 --- a/game/missiongenerator/aircraft/waypoints/casingress.py +++ /dev/null @@ -1,40 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import EngageTargets, EngageTargetsInZone, Targets - -from game.ato.flightplans.cas import CasFlightPlan -from game.utils import nautical_miles -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class CasIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - if isinstance(self.flight.flight_plan, CasFlightPlan): - patrol_center = ( - self.flight.flight_plan.layout.patrol_start.position - + self.flight.flight_plan.layout.patrol_end.position - ) / 2 - waypoint.add_task( - EngageTargetsInZone( - position=patrol_center, - radius=int(self.flight.flight_plan.engagement_distance.meters), - targets=[ - Targets.All.GroundUnits.GroundVehicles, - Targets.All.GroundUnits.AirDefence.AAA, - Targets.All.GroundUnits.Infantry, - ], - ) - ) - else: - logging.error("No CAS waypoint found. Falling back to search and engage") - waypoint.add_task( - EngageTargets( - max_distance=int(nautical_miles(10).meters), - targets=[ - Targets.All.GroundUnits.GroundVehicles, - Targets.All.GroundUnits.AirDefence.AAA, - Targets.All.GroundUnits.Infantry, - ], - ) - ) diff --git a/game/missiongenerator/aircraft/waypoints/deadingress.py b/game/missiongenerator/aircraft/waypoints/deadingress.py deleted file mode 100644 index 36c0886ab..000000000 --- a/game/missiongenerator/aircraft/waypoints/deadingress.py +++ /dev/null @@ -1,37 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import AttackGroup, OptECMUsing, WeaponType - -from game.theater import TheaterGroundObject -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class DeadIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - self.register_special_waypoints(self.waypoint.targets) - - target = self.package.target - if not isinstance(target, TheaterGroundObject): - logging.error( - "Unexpected target type for DEAD mission: %s", - target.__class__.__name__, - ) - return - - for group in target.groups: - miz_group = self.mission.find_group(group.group_name) - if miz_group is None: - logging.error( - f"Could not find group for DEAD mission {group.group_name}" - ) - continue - - task = AttackGroup( - miz_group.id, weapon_type=WeaponType.Auto, group_attack=True - ) - waypoint.tasks.append(task) - - # Preemptively use ECM to better avoid getting swatted. - ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar) - waypoint.tasks.append(ecm_option) diff --git a/game/missiongenerator/aircraft/waypoints/default.py b/game/missiongenerator/aircraft/waypoints/default.py deleted file mode 100644 index c60f69fe7..000000000 --- a/game/missiongenerator/aircraft/waypoints/default.py +++ /dev/null @@ -1,5 +0,0 @@ -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class DefaultWaypointBuilder(PydcsWaypointBuilder): - pass diff --git a/game/missiongenerator/aircraft/waypoints/joinpoint.py b/game/missiongenerator/aircraft/waypoints/joinpoint.py deleted file mode 100644 index 5cbd9d9f7..000000000 --- a/game/missiongenerator/aircraft/waypoints/joinpoint.py +++ /dev/null @@ -1,95 +0,0 @@ -from typing import List, Type - -from dcs.point import MovingPoint -from dcs.task import ( - ControlledTask, - EngageTargets, - OptECMUsing, - OptFormation, - TargetType, - Targets, -) - -from game.ato import FlightType -from game.utils import nautical_miles -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class JoinPointBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - if self.flight.flight_type == FlightType.ESCORT: - self.configure_escort_tasks( - waypoint, - [ - Targets.All.Air.Planes.Fighters, - Targets.All.Air.Planes.MultiroleFighters, - ], - ) - - waypoint.tasks.append(OptFormation.line_abreast_open()) - - elif self.flight.flight_type == FlightType.SEAD_ESCORT: - self.configure_escort_tasks( - waypoint, [Targets.All.GroundUnits.AirDefence.AAA.SAMRelated] - ) - - # Let the AI use ECM to preemptively defend themselves. - ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar) - waypoint.tasks.append(ecm_option) - - waypoint.tasks.append(OptFormation.line_abreast_open()) - - elif not self.flight.flight_type.is_air_to_air: - # Capture any non A/A type to avoid issues with SPJs that use the primary radar such as the F/A-18C. - # You can bully them with STT to not be able to fire radar guided missiles at you, - # so best choice is to not let them perform jamming for now. - - # Let the AI use ECM to defend themselves. - ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfOnlyLockByRadar) - waypoint.tasks.append(ecm_option) - - waypoint.tasks.append(OptFormation.finger_four_open()) - - @staticmethod - def configure_escort_tasks( - waypoint: MovingPoint, target_types: List[Type[TargetType]] - ) -> None: - # Ideally we would use the escort mission type and escort task to have - # the AI automatically but the AI only escorts AI flights while they are - # traveling between waypoints. When an AI flight performs an attack - # (such as attacking the mission target), AI escorts wander aimlessly - # until the escorted group resumes its flight plan. - # - # As such, we instead use the Search Then Engage task, which is an - # enroute task that causes the AI to follow their flight plan and engage - # enemies of the set type within a certain distance. The downside to - # this approach is that AI escorts are no longer related to the group - # they are escorting, aside from the fact that they fly a similar flight - # plan at the same time. With Escort, the escorts will follow the - # escorted group out of the area. The strike element may or may not fly - # directly over the target, and they may or may not require multiple - # attack runs. For the escort flight we must just assume a flight plan - # for the escort to fly. If the strike flight doesn't need to overfly - # the target, the escorts are needlessly going in harms way. If the - # strike flight needs multiple passes, the escorts may leave before the - # escorted aircraft do. - # - # Another possible option would be to use Search Then Engage for join -> - # ingress and egress -> split, but use a Search Then Engage in Zone task - # for the target area that is set to end on a flag flip that occurs when - # the strike aircraft finish their attack task. - # - # https://forums.eagle.ru/topic/251798-options-for-alternate-ai-escort-behavior - waypoint.add_task( - ControlledTask( - EngageTargets( - # TODO: From doctrine. - max_distance=int(nautical_miles(30).meters), - targets=target_types, - ) - ) - ) - - # We could set this task to end at the split point. pydcs doesn't - # currently support that task end condition though, and we don't really - # need it. diff --git a/game/missiongenerator/aircraft/waypoints/landingpoint.py b/game/missiongenerator/aircraft/waypoints/landingpoint.py deleted file mode 100644 index 69c1e71d4..000000000 --- a/game/missiongenerator/aircraft/waypoints/landingpoint.py +++ /dev/null @@ -1,13 +0,0 @@ -from dcs.point import MovingPoint, PointAction - -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class LandingPointBuilder(PydcsWaypointBuilder): - def build(self) -> MovingPoint: - waypoint = super().build() - waypoint.type = "Land" - waypoint.action = PointAction.Landing - if (control_point := self.waypoint.control_point) is not None: - waypoint.airdrome_id = control_point.airdrome_id_for_landing - return waypoint diff --git a/game/missiongenerator/aircraft/waypoints/landingzone.py b/game/missiongenerator/aircraft/waypoints/landingzone.py deleted file mode 100644 index 338bb97c2..000000000 --- a/game/missiongenerator/aircraft/waypoints/landingzone.py +++ /dev/null @@ -1,17 +0,0 @@ -from dcs.point import MovingPoint -from dcs.task import Land - - -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class LandingZoneBuilder(PydcsWaypointBuilder): - def build(self) -> MovingPoint: - waypoint = super().build() - # Create a landing task, currently only for Helos! - # Calculate a landing point with a small buffer to prevent AI from landing - # directly at the static ammo depot and exploding - landing_point = waypoint.position.random_point_within(15, 5) - # Use Land Task with 30s duration for helos - waypoint.add_task(Land(landing_point, duration=30)) - return waypoint diff --git a/game/missiongenerator/aircraft/waypoints/ocaaircraftingress.py b/game/missiongenerator/aircraft/waypoints/ocaaircraftingress.py deleted file mode 100644 index cf5dc5e7a..000000000 --- a/game/missiongenerator/aircraft/waypoints/ocaaircraftingress.py +++ /dev/null @@ -1,32 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import EngageTargetsInZone, Targets - -from game.theater import Airfield -from game.utils import nautical_miles -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class OcaAircraftIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - target = self.package.target - if not isinstance(target, Airfield): - logging.error( - "Unexpected target type for OCA Strike mission: %s", - target.__class__.__name__, - ) - return - - task = EngageTargetsInZone( - position=target.position, - # Al Dhafra is 4 nm across at most. Add a little wiggle room in case - # the airport position from DCS is not centered. - radius=int(nautical_miles(3).meters), - targets=[Targets.All.Air], - ) - task.params["attackQtyLimit"] = False - task.params["directionEnabled"] = False - task.params["altitudeEnabled"] = False - task.params["groupAttack"] = True - waypoint.tasks.append(task) diff --git a/game/missiongenerator/aircraft/waypoints/ocarunwayingress.py b/game/missiongenerator/aircraft/waypoints/ocarunwayingress.py deleted file mode 100644 index e1ec97386..000000000 --- a/game/missiongenerator/aircraft/waypoints/ocarunwayingress.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import ( - Bombing, - BombingRunway, - OptFormation, - WeaponType as DcsWeaponType, -) - -from game.data.weapons import WeaponType -from game.theater import Airfield -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class OcaRunwayIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - target = self.package.target - if not isinstance(target, Airfield): - logging.error( - "Unexpected target type for runway bombing mission: %s", - target.__class__.__name__, - ) - return - - # The BombingRunway task in DCS does not use LGBs, which necessitates special handling - # by using the Bombing task instead. See https://github.com/dcs-liberation/dcs_liberation/issues/894 - # for more details. - # The LGB work around assumes the Airfield position in DCS is on a runway, which seems - # to be the case for most if not all airfields. - if self.flight.any_member_has_weapon_of_type(WeaponType.LGB): - waypoint.tasks.append( - Bombing( - position=target.position, - group_attack=True, - weapon_type=DcsWeaponType.Guided, - ) - ) - else: # Use BombingRunway task for all other weapon types - waypoint.tasks.append( - BombingRunway(airport_id=target.airport.id, group_attack=True) - ) - waypoint.tasks.append(OptFormation.trail_open()) diff --git a/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py b/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py deleted file mode 100644 index e003284d3..000000000 --- a/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py +++ /dev/null @@ -1,131 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from typing import Any, Iterable, Union - -from dcs import Mission -from dcs.planes import AJS37, F_14B, JF_17 -from dcs.point import MovingPoint, PointAction -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight, FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.ato.traveltime import GroundSpeed -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.missiongenerator.missiondata import MissionData -from game.theater import MissionTarget, TheaterUnit -from game.unitmap import UnitMap - -TARGET_WAYPOINTS = ( - FlightWaypointType.TARGET_GROUP_LOC, - FlightWaypointType.TARGET_POINT, - FlightWaypointType.TARGET_SHIP, -) - - -class PydcsWaypointBuilder: - def __init__( - self, - waypoint: FlightWaypoint, - group: FlyingGroup[Any], - flight: Flight, - mission: Mission, - now: datetime, - mission_data: MissionData, - unit_map: UnitMap, - generated_waypoint_idx: int, - ) -> None: - self.waypoint = waypoint - self.group = group - self.package = flight.package - self.flight = flight - self.mission = mission - self.now = now - self.mission_data = mission_data - self.unit_map = unit_map - self.generated_waypoint_idx = generated_waypoint_idx - - def dcs_name_for_waypoint(self) -> str: - return self.waypoint.name - - def build(self) -> MovingPoint: - waypoint = self.group.add_waypoint( - self.waypoint.position, - self.waypoint.alt.meters, - # The speed we pass will be overridden for most waypoints because we'll set - # a TOT and leave the speed up to the AI, but for the few types of waypoints - # that don't have TOTs (e.g. nav points), we set a reasonable cruise speed - # to pydcs doesn't assign the default of 600kph ground speed (which is very - # slow at most altitudes). - # - # Calling GroundSpeed.for_flight isn't really a correct fix here. We ought - # to be using FlightPlan.speed_between_waypoints, but the way the waypoint - # builder is called makes it difficult to track the previous waypoint. This - # is probably good enough for a stop gap, and most of the flight planning - # code is hopefully being rewritten soon anyway. - # - # https://github.com/dcs-liberation/dcs_liberation/issues/3113 - speed=GroundSpeed.for_flight(self.flight, self.waypoint.alt).kph, - name=self.dcs_name_for_waypoint(), - ) - - if self.waypoint.flyover: - waypoint.action = PointAction.FlyOverPoint - # It seems we need to leave waypoint.type exactly as it is even - # though it's set to "Turning Point". If I set this to "Fly Over - # Point" and then save the mission in the ME DCS resets it. - if self.flight.client_count > 0: - # Set Altitute to 0 AGL for player flights so that they can slave target pods or weapons to the waypoint - waypoint.alt = 0 - waypoint.alt_type = "RADIO" - - waypoint.alt_type = self.waypoint.alt_type - tot = self.flight.flight_plan.tot_for_waypoint(self.waypoint) - if tot is not None: - self.set_waypoint_tot(waypoint, tot, self.generated_waypoint_idx) - self.add_tasks(waypoint) - return waypoint - - def add_tasks(self, waypoint: MovingPoint) -> None: - ctx = TaskContext(self.now) - for action in self.waypoint.actions: - for task in action.iter_tasks(ctx): - waypoint.add_task(task) - for option in self.waypoint.options.values(): - for task in option.iter_tasks(ctx): - waypoint.add_task(task) - - def set_waypoint_tot( - self, waypoint: MovingPoint, tot: datetime, waypoint_index: int - ) -> None: - self.waypoint.tot = tot - if not self._viggen_client_tot(): - waypoint.ETA = int((tot - self.now).total_seconds()) - waypoint.ETA_locked = True - # The first waypoint must always have a locked speed (see the bug). Other - # waypoints cannot lock both a speed and an ETA, so we need to clear the - # speed lock when setting a TOT. - # https://github.com/dcs-liberation/dcs_liberation/issues/3195 - waypoint.speed_locked = waypoint_index == 0 - - def _viggen_client_tot(self) -> bool: - """Viggen player aircraft consider any waypoint with a TOT set to be a target ("M") waypoint. - If the flight is a player controlled Viggen flight, no TOT should be set on any waypoint except actual target waypoints. - """ - if ( - self.flight.client_count > 0 - and self.flight.unit_type.dcs_unit_type == AJS37 - ) and (self.waypoint.waypoint_type not in TARGET_WAYPOINTS): - return True - else: - return False - - def register_special_waypoints( - self, targets: Iterable[Union[MissionTarget, TheaterUnit]] - ) -> None: - """Create special target waypoints for various aircraft""" - for i, t in enumerate(targets): - if self.group.units[0].unit_type == JF_17 and i < 4: - self.group.add_nav_target_point(t.position, "PP" + str(i + 1)) - if self.group.units[0].unit_type == F_14B and i == 0: - self.group.add_nav_target_point(t.position, "ST") diff --git a/game/missiongenerator/aircraft/waypoints/racetrack.py b/game/missiongenerator/aircraft/waypoints/racetrack.py deleted file mode 100644 index 5a14dd4dc..000000000 --- a/game/missiongenerator/aircraft/waypoints/racetrack.py +++ /dev/null @@ -1,83 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import ( - ActivateBeaconCommand, - ControlledTask, - EngageTargets, - OrbitAction, - Tanker, - Targets, -) - -from game.ato import FlightType -from game.ato.flightplans.patrolling import PatrollingFlightPlan -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class RaceTrackBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - flight_plan = self.flight.flight_plan - - if not isinstance(flight_plan, PatrollingFlightPlan): - flight_plan_type = flight_plan.__class__.__name__ - logging.error( - f"Cannot create race track for {self.flight} because " - f"{flight_plan_type} does not define a patrol." - ) - return - - # NB: It's important that the engage task comes before the orbit task. - # Though they're on the same waypoint, if the orbit task comes first it - # is their first priority and they will not engage any targets because - # they're fully focused on orbiting. If the STE task is first, they will - # engage targets if available and orbit if they find nothing to shoot. - if self.flight.flight_type is FlightType.REFUELING: - self.configure_refueling_actions(waypoint) - - # TODO: Move the properties of this task into the flight plan? - # CAP is the only current user of this so it's not a big deal, but might - # be good to make this usable for things like BAI when we add that - # later. - cap_types = {FlightType.BARCAP, FlightType.TARCAP} - if self.flight.flight_type in cap_types: - engagement_distance = int(flight_plan.engagement_distance.meters) - waypoint.tasks.append( - EngageTargets( - max_distance=engagement_distance, targets=[Targets.All.Air] - ) - ) - - orbit = OrbitAction( - altitude=waypoint.alt, - pattern=OrbitAction.OrbitPattern.RaceTrack, - speed=int(flight_plan.patrol_speed.kph), - ) - - racetrack = ControlledTask(orbit) - loiter_duration = flight_plan.patrol_end_time - self.now - racetrack.stop_after_time(int(loiter_duration.total_seconds())) - waypoint.add_task(racetrack) - - def configure_refueling_actions(self, waypoint: MovingPoint) -> None: - waypoint.add_task(Tanker()) - - if self.flight.unit_type.dcs_unit_type.tacan: - tanker_info = self.mission_data.tankers[-1] - tacan = tanker_info.tacan - tacan_callsign = { - "Texaco": "TEX", - "Arco": "ARC", - "Shell": "SHL", - }.get(tanker_info.callsign) - - waypoint.add_task( - ActivateBeaconCommand( - tacan.number, - tacan.band.value, - tacan_callsign, - bearing=True, - unit_id=self.group.units[0].id, - aa=True, - ) - ) diff --git a/game/missiongenerator/aircraft/waypoints/racetrackend.py b/game/missiongenerator/aircraft/waypoints/racetrackend.py deleted file mode 100644 index c1744445d..000000000 --- a/game/missiongenerator/aircraft/waypoints/racetrackend.py +++ /dev/null @@ -1,22 +0,0 @@ -import logging - -from dcs.point import MovingPoint - -from game.ato.flightplans.patrolling import PatrollingFlightPlan -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class RaceTrackEndBuilder(PydcsWaypointBuilder): - def build(self) -> MovingPoint: - waypoint = super().build() - - if not isinstance(self.flight.flight_plan, PatrollingFlightPlan): - flight_plan_type = self.flight.flight_plan.__class__.__name__ - logging.error( - f"Cannot create race track for {self.flight} because " - f"{flight_plan_type} does not define a patrol." - ) - return waypoint - - self.waypoint.departure_time = self.flight.flight_plan.patrol_end_time - return waypoint diff --git a/game/missiongenerator/aircraft/waypoints/recoverytanker.py b/game/missiongenerator/aircraft/waypoints/recoverytanker.py deleted file mode 100644 index 70ded28fc..000000000 --- a/game/missiongenerator/aircraft/waypoints/recoverytanker.py +++ /dev/null @@ -1,68 +0,0 @@ -from dcs.point import MovingPoint -from dcs.task import ActivateBeaconCommand, RecoveryTanker, Tanker - -from game.ato import FlightType -from game.utils import feet, knots -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class RecoveryTankerBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - assert self.flight.flight_type == FlightType.REFUELING - - # Tanker task required in conjunction with RecoveryTanker task. - # See link below for details. - # https://github.com/dcs-liberation/dcs_liberation/issues/2771 - waypoint.add_task(Tanker()) - - group_id = self._get_carrier_group_id() - speed = knots(250).meters_per_second - altitude = feet(6000).meters - - # Last waypoint has index of 1. - # Give the tanker a end condition of the last carrier waypoint. - # If the carrier ever gets more than one waypoint this approach needs to change. - last_waypoint = 2 - recovery_tanker = RecoveryTanker(group_id, speed, altitude, last_waypoint) - - waypoint.add_task(recovery_tanker) - - self.configure_tanker_tacan(waypoint) - - def _get_carrier_group_id(self) -> int: - name = self.package.target.name - carrier_position = self.package.target.position - theater_objects = self.unit_map.theater_objects - for key, value in theater_objects.items(): - # Check name and position in case there are multiple of same carrier. - if ( - name in key - and value.theater_unit.position.distance_to_point(carrier_position) - < 1.0 - ): - return value.dcs_group_id - raise RuntimeError( - f"Could not find a carrier in the mission matching {name} at " - f"({carrier_position.x}, {carrier_position.y})" - ) - - def configure_tanker_tacan(self, waypoint: MovingPoint) -> None: - if self.flight.unit_type.dcs_unit_type.tacan: - tanker_info = self.mission_data.tankers[-1] - tacan = tanker_info.tacan - tacan_callsign = { - "Texaco": "TEX", - "Arco": "ARC", - "Shell": "SHL", - }.get(tanker_info.callsign) - - waypoint.add_task( - ActivateBeaconCommand( - tacan.number, - tacan.band.value, - tacan_callsign, - bearing=True, - unit_id=self.group.units[0].id, - aa=True, - ) - ) diff --git a/game/missiongenerator/aircraft/waypoints/refuel.py b/game/missiongenerator/aircraft/waypoints/refuel.py deleted file mode 100644 index 1fbc7d5d7..000000000 --- a/game/missiongenerator/aircraft/waypoints/refuel.py +++ /dev/null @@ -1,12 +0,0 @@ -from dcs.point import MovingPoint -from dcs.task import RefuelingTaskAction - -from game.ato import FlightType -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class RefuelPointBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - if self.package.has_flight_with_task(FlightType.REFUELING): - waypoint.add_task(RefuelingTaskAction()) - return super().add_tasks(waypoint) diff --git a/game/missiongenerator/aircraft/waypoints/seadingress.py b/game/missiongenerator/aircraft/waypoints/seadingress.py deleted file mode 100644 index 4893ff4e9..000000000 --- a/game/missiongenerator/aircraft/waypoints/seadingress.py +++ /dev/null @@ -1,93 +0,0 @@ -import logging - -from dcs.point import MovingPoint -from dcs.task import ( - AttackGroup, - ControlledTask, - EngageGroup, - Expend, - OptECMUsing, - SwitchWaypoint, - WeaponType as DcsWeaponType, -) - -from game.data.weapons import WeaponType -from game.theater import TheaterGroundObject -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class SeadIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - self.register_special_waypoints(self.waypoint.targets) - - target = self.package.target - if not isinstance(target, TheaterGroundObject): - logging.error( - "Unexpected target type for SEAD mission: %s", - target.__class__.__name__, - ) - return - - for group in target.groups: - miz_group = self.mission.find_group(group.group_name) - if miz_group is None: - logging.error( - f"Could not find group for SEAD mission {group.group_name}" - ) - continue - - if self.flight.any_member_has_weapon_of_type(WeaponType.ARM): - # Special handling for ARM Weapon types: - # The SEAD flight will Search for the targeted group and then engage it - # if it is found only. This will prevent AI from having huge problems - # when skynet is enabled and the Radar is not emitting. They dive - # into the SAM instead of waiting for it to come alive - engage_task = EngageGroup(miz_group.id) - engage_task.params["weaponType"] = DcsWeaponType.Guided.value - engage_task.params["groupAttack"] = True - engage_task.params["expend"] = Expend.All.value - waypoint.tasks.append(engage_task) - elif self.flight.any_member_has_weapon_of_type(WeaponType.DECOY): - # Special handling for DECOY weapon types: - # - Specify that DECOY weapon type is used in AttackGroup task so that - # the flight actually launches the decoy. See link below for details - # https://github.com/dcs-liberation/dcs_liberation/issues/2780 - # - Set a stop condition of 120 seconds so that the flight does not continue - # press the engagement as a DCS limitation means the RTB on winchester - # does not work well with decoys. See link below for details. - # https://github.com/dcs-liberation/dcs_liberation/issues/2781 - # This stop condition will allow the SwitchWaypoint task defined below - # to kick in. - attack_task = AttackGroup( - miz_group.id, - weapon_type=DcsWeaponType.Decoy, - group_attack=True, - expend=Expend.All, - ) - attack_task_control = ControlledTask(attack_task) - attack_task_control.stop_after_duration(120) - waypoint.tasks.append(attack_task_control) - else: - # All non ARM and non DECOY types will use the normal AttackGroup Task - attack_task = AttackGroup( - miz_group.id, - weapon_type=DcsWeaponType.Guided, - group_attack=True, - expend=Expend.All, - ) - waypoint.tasks.append(attack_task) - - # Preemptively use ECM to better avoid getting swatted. - ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfDetectedLockByRadar) - waypoint.tasks.append(ecm_option) - - # For DECOY type flights, setup a waypoint task to skip the target waypoint after - # the attack task is complete. This is achieved using a switch waypoint task from the - # INGRESS point to the SPLIT point. This tasking prevents the flights continuing to - # overfly the target. See link below for the details of this issue - # https://github.com/dcs-liberation/dcs_liberation/issues/2781 - if self.flight.any_member_has_weapon_of_type(WeaponType.DECOY): - switch_waypoint_task = SwitchWaypoint( - self.generated_waypoint_idx, self.generated_waypoint_idx + 2 - ) - waypoint.tasks.append(switch_waypoint_task) diff --git a/game/missiongenerator/aircraft/waypoints/splitpoint.py b/game/missiongenerator/aircraft/waypoints/splitpoint.py deleted file mode 100644 index d99e8c717..000000000 --- a/game/missiongenerator/aircraft/waypoints/splitpoint.py +++ /dev/null @@ -1,18 +0,0 @@ -from dcs.point import MovingPoint -from dcs.task import OptECMUsing, OptFormation - -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class SplitPointBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - if not self.flight.flight_type.is_air_to_air: - # Capture any non A/A type to avoid issues with SPJs that use the primary radar such as the F/A-18C. - # You can bully them with STT to not be able to fire radar guided missiles at you, - # so best choice is to not let them perform jamming for now. - - # Let the AI use ECM to defend themselves. - ecm_option = OptECMUsing(value=OptECMUsing.Values.UseIfOnlyLockByRadar) - waypoint.tasks.append(ecm_option) - - waypoint.tasks.append(OptFormation.finger_four_close()) diff --git a/game/missiongenerator/aircraft/waypoints/strikeingress.py b/game/missiongenerator/aircraft/waypoints/strikeingress.py deleted file mode 100644 index 89daa74f7..000000000 --- a/game/missiongenerator/aircraft/waypoints/strikeingress.py +++ /dev/null @@ -1,45 +0,0 @@ -import copy - -from dcs import Point -from dcs.planes import B_17G, B_52H, Tu_22M3 -from dcs.point import MovingPoint -from dcs.task import Bombing, Expend, OptFormation, WeaponType - -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class StrikeIngressBuilder(PydcsWaypointBuilder): - def add_tasks(self, waypoint: MovingPoint) -> None: - if self.group.units[0].unit_type in [B_17G, B_52H, Tu_22M3]: - self.add_bombing_tasks(waypoint) - else: - self.add_strike_tasks(waypoint) - - waypoint.tasks.append(OptFormation.trail_open()) - - def add_bombing_tasks(self, waypoint: MovingPoint) -> None: - targets = self.waypoint.targets - if not targets: - return - - center: Point = copy.copy(targets[0].position) - for target in targets[1:]: - center += target.position - center /= len(targets) - bombing = Bombing( - center, weapon_type=WeaponType.Bombs, expend=Expend.All, group_attack=True - ) - waypoint.tasks.append(bombing) - - def add_strike_tasks(self, waypoint: MovingPoint) -> None: - for target in self.waypoint.targets: - bombing = Bombing( - target.position, weapon_type=WeaponType.Auto, group_attack=True - ) - # If there is only one target, drop all ordnance in one pass. - if len(self.waypoint.targets) == 1: - bombing.params["expend"] = Expend.All.value - waypoint.tasks.append(bombing) - - # Register special waypoints - self.register_special_waypoints(self.waypoint.targets) diff --git a/game/missiongenerator/aircraft/waypoints/target.py b/game/missiongenerator/aircraft/waypoints/target.py deleted file mode 100644 index 188c0cdd0..000000000 --- a/game/missiongenerator/aircraft/waypoints/target.py +++ /dev/null @@ -1,14 +0,0 @@ -from .pydcswaypointbuilder import PydcsWaypointBuilder - - -class TargetBuilder(PydcsWaypointBuilder): - """Waypoint builder for target waypoint types. - - This handles both precise target locations (TARGET_POINT) and target areas - (TARGET_GROUP_LOC). - """ - - def dcs_name_for_waypoint(self) -> str: - if self.flight.unit_type.use_f15e_waypoint_names: - return f"#T {self.waypoint.name}" - return super().dcs_name_for_waypoint() diff --git a/game/missiongenerator/aircraft/waypoints/waypointgenerator.py b/game/missiongenerator/aircraft/waypoints/waypointgenerator.py deleted file mode 100644 index 69ac6ef03..000000000 --- a/game/missiongenerator/aircraft/waypoints/waypointgenerator.py +++ /dev/null @@ -1,296 +0,0 @@ -import itertools -import random -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import Any - -from dcs import Mission -from dcs.action import AITaskPush, ActivateGroup -from dcs.condition import CoalitionHasAirdrome, TimeAfter -from dcs.planes import AJS37 -from dcs.task import StartCommand -from dcs.triggers import Event, TriggerOnce, TriggerRule -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight, FlightWaypoint -from game.ato.flightstate import InFlight, WaitingForStart -from game.ato.flightwaypointtype import FlightWaypointType -from game.ato.starttype import StartType -from game.missiongenerator.aircraft.waypoints.cargostop import CargoStopBuilder -from game.missiongenerator.aircraft.waypoints.recoverytanker import ( - RecoveryTankerBuilder, -) -from game.missiongenerator.missiondata import MissionData -from game.settings import Settings -from game.unitmap import UnitMap -from game.utils import pairwise -from .antishipingress import AntiShipIngressBuilder -from .baiingress import BaiIngressBuilder -from .casingress import CasIngressBuilder -from .deadingress import DeadIngressBuilder -from .default import DefaultWaypointBuilder -from .joinpoint import JoinPointBuilder -from .landingpoint import LandingPointBuilder -from .landingzone import LandingZoneBuilder -from .ocaaircraftingress import OcaAircraftIngressBuilder -from .ocarunwayingress import OcaRunwayIngressBuilder -from .pydcswaypointbuilder import PydcsWaypointBuilder, TARGET_WAYPOINTS -from .racetrack import RaceTrackBuilder -from .racetrackend import RaceTrackEndBuilder -from .refuel import RefuelPointBuilder -from .seadingress import SeadIngressBuilder -from .splitpoint import SplitPointBuilder -from .strikeingress import StrikeIngressBuilder -from .target import TargetBuilder - - -class WaypointGenerator: - def __init__( - self, - flight: Flight, - group: FlyingGroup[Any], - mission: Mission, - time: datetime, - settings: Settings, - mission_data: MissionData, - unit_map: UnitMap, - ) -> None: - self.flight = flight - self.group = group - self.mission = mission - self.time = time - self.settings = settings - self.mission_data = mission_data - self.unit_map = unit_map - - def create_waypoints(self) -> tuple[timedelta, list[FlightWaypoint]]: - for waypoint in self.flight.points: - waypoint.tot = None - - waypoints = self.flight.flight_plan.waypoints - mission_start_time = self.set_takeoff_time(waypoints[0]) - - filtered_points: list[FlightWaypoint] = [] - for point in self.flight.points: - if point.only_for_player and not self.flight.client_count: - continue - if isinstance(self.flight.state, InFlight): - if point == self.flight.state.current_waypoint: - # We don't need to build this waypoint because pydcs did that for - # us, but we do need to configure the tasks for it so that mid- - # mission aircraft starting at a waypoint with tasks behave - # correctly. - self.builder_for_waypoint(point, 1).add_tasks(self.group.points[0]) - if not self.flight.state.has_passed_waypoint(point): - filtered_points.append(point) - else: - filtered_points.append(point) - # Only add 1 target waypoint for Viggens. This only affects player flights, the - # Viggen can't have more than 9 waypoints which leaves us with two target point - # under the current flight plans. - # TODO: Make this smarter. It currently targets a random unit in the group. - # This could be updated to make it pick the "best" two targets in the group. - if self.flight.unit_type.dcs_unit_type is AJS37 and self.flight.client_count: - viggen_target_points = [ - (idx, point) - for idx, point in enumerate(filtered_points) - if point.waypoint_type in TARGET_WAYPOINTS - ] - if viggen_target_points: - keep_target = viggen_target_points[ - random.randint(0, len(viggen_target_points) - 1) - ] - filtered_points = [ - point - for idx, point in enumerate(filtered_points) - if ( - point.waypoint_type not in TARGET_WAYPOINTS - or idx == keep_target[0] - ) - ] - - for idx, point in enumerate(filtered_points): - # We add 2 to idx to get the generated waypoint index as - # 1) pydcs seems to decrement the index by 1 and - # 2) DCS starts the first waypoint at index 1 as 0 is the starting position - self.builder_for_waypoint(point, idx + 2).build() - - # Set here rather than when the FlightData is created so they waypoints - # have their TOTs and fuel minimums set. Once we're more confident in our fuel - # estimation ability the minimum fuel amounts will be calculated during flight - # plan construction, but for now it's only used by the kneeboard so is generated - # late. - self._estimate_min_fuel_for(waypoints) - return mission_start_time, waypoints - - def builder_for_waypoint( - self, waypoint: FlightWaypoint, generated_waypoint_index: int - ) -> PydcsWaypointBuilder: - builders = { - FlightWaypointType.CARGO_STOP: CargoStopBuilder, - FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder, - FlightWaypointType.INGRESS_ANTI_SHIP: AntiShipIngressBuilder, - FlightWaypointType.INGRESS_BAI: BaiIngressBuilder, - FlightWaypointType.INGRESS_CAS: CasIngressBuilder, - FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder, - FlightWaypointType.INGRESS_OCA_AIRCRAFT: OcaAircraftIngressBuilder, - FlightWaypointType.INGRESS_OCA_RUNWAY: OcaRunwayIngressBuilder, - FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder, - FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder, - FlightWaypointType.JOIN: JoinPointBuilder, - FlightWaypointType.LANDING_POINT: LandingPointBuilder, - FlightWaypointType.PATROL: RaceTrackEndBuilder, - FlightWaypointType.PATROL_TRACK: RaceTrackBuilder, - FlightWaypointType.PICKUP_ZONE: LandingZoneBuilder, - FlightWaypointType.RECOVERY_TANKER: RecoveryTankerBuilder, - FlightWaypointType.REFUEL: RefuelPointBuilder, - FlightWaypointType.SPLIT: SplitPointBuilder, - FlightWaypointType.TARGET_GROUP_LOC: TargetBuilder, - FlightWaypointType.TARGET_POINT: TargetBuilder, - } - builder = builders.get(waypoint.waypoint_type, DefaultWaypointBuilder) - return builder( - waypoint, - self.group, - self.flight, - self.mission, - self.time, - self.mission_data, - self.unit_map, - generated_waypoint_index, - ) - - def _estimate_min_fuel_for(self, waypoints: list[FlightWaypoint]) -> None: - if self.flight.unit_type.fuel_consumption is None: - return - - consumption = self.flight.unit_type.fuel_consumption - min_fuel: float = consumption.min_safe - - # The flight plan (in reverse) up to and including the arrival point. - main_flight_plan: Iterator[FlightWaypoint] = reversed(waypoints) - try: - while waypoint := next(main_flight_plan): - if waypoint.waypoint_type is FlightWaypointType.LANDING_POINT: - waypoint.min_fuel = min_fuel - main_flight_plan = itertools.chain([waypoint], main_flight_plan) - break - except StopIteration: - # Some custom flight plan without a landing point. Skip it. - return - - for b, a in pairwise(main_flight_plan): - for_leg = self.flight.flight_plan.fuel_consumption_between_points(a, b) - if for_leg is None: - continue - min_fuel += for_leg - a.min_fuel = min_fuel - - def set_takeoff_time(self, waypoint: FlightWaypoint) -> timedelta: - force_delay = False - if isinstance(self.flight.state, WaitingForStart): - delay = self.flight.state.time_remaining(self.time) - elif ( - # The first two clauses capture the flight states that we want to adjust. We - # don't want to delay any flights that are already in flight or on the - # runway. - not self.flight.state.in_flight - and self.flight.state.spawn_type is not StartType.RUNWAY - and self.flight.departure.is_fleet - and not self.flight.client_count - ): - # https://github.com/dcs-liberation/dcs_liberation/issues/1309 - # Without a delay, AI aircraft will be spawned on the sixpack, which other - # AI planes of course want to taxi through, deadlocking the carrier deck. - # Delaying AI carrier deck spawns by one second for some reason causes DCS - # to spawn those aircraft elsewhere, avoiding the traffic jam. - delay = timedelta(seconds=1) - force_delay = True - else: - delay = timedelta() - - if force_delay or self.should_delay_flight(): - if self.should_activate_late(): - # Late activation causes the aircraft to not be spawned - # until triggered. - self.set_activation_time(delay) - elif self.flight.start_type is StartType.COLD: - # Setting the start time causes the AI to wait until the - # specified time to begin their startup sequence. - self.set_startup_time(delay) - - # And setting *our* waypoint TOT causes the takeoff time to show up in - # the player's kneeboard. - waypoint.tot = self.flight.flight_plan.takeoff_time() - return delay - - def set_activation_time(self, delay: timedelta) -> None: - # Note: Late activation causes the waypoint TOTs to look *weird* in the - # mission editor. Waypoint times will be relative to the group - # activation time rather than in absolute local time. A flight delayed - # until 09:10 when the overall mission start time is 09:00, with a join - # time of 09:30 will show the join time as 00:30, not 09:30. - self.group.late_activation = True - - activation_trigger = TriggerOnce( - Event.NoEvent, f"FlightLateActivationTrigger{self.group.id}" - ) - activation_trigger.add_condition(TimeAfter(seconds=int(delay.total_seconds()))) - - self.prevent_spawn_at_hostile_airbase(activation_trigger) - activation_trigger.add_action(ActivateGroup(self.group.id)) - self.mission.triggerrules.triggers.append(activation_trigger) - - def prevent_spawn_at_hostile_airbase(self, trigger: TriggerRule) -> None: - # Prevent delayed flights from spawning at airbases if they were - # captured before they've spawned. - if (airport := self.flight.departure.dcs_airport) is not None: - trigger.add_condition( - CoalitionHasAirdrome( - self.flight.squadron.coalition.coalition_id, airport.id - ) - ) - - def set_startup_time(self, delay: timedelta) -> None: - # Uncontrolled causes the AI unit to spawn, but not begin startup. - self.group.uncontrolled = True - - activation_trigger = TriggerOnce( - Event.NoEvent, f"FlightStartTrigger{self.group.id}" - ) - activation_trigger.add_condition(TimeAfter(seconds=int(delay.total_seconds()))) - - self.prevent_spawn_at_hostile_airbase(activation_trigger) - self.group.add_trigger_action(StartCommand()) - activation_trigger.add_action(AITaskPush(self.group.id, len(self.group.tasks))) - self.mission.triggerrules.triggers.append(activation_trigger) - - def should_delay_flight(self) -> bool: - if not isinstance(self.flight.state, WaitingForStart): - return False - - if not self.flight.client_count: - return True - - if self.flight.state.time_remaining(self.time) < timedelta(minutes=10): - # Don't bother delaying client flights with short start delays. Much more - # than ten minutes starts to eat into fuel a bit more (especially for - # something fuel limited like a Harrier). - return False - - return not self.settings.never_delay_player_flights - - def should_activate_late(self) -> bool: - if self.flight.start_type is not StartType.COLD: - # Avoid spawning aircraft in the air or on the runway until it's - # time for their mission. Also avoid burning through gas spawning - # hot aircraft hours before their takeoff time. - return True - - if self.flight.departure.is_fleet: - # Carrier spawns will crowd the carrier deck, especially without - # super carrier. - # TODO: Is there enough parking on the supercarrier? - return True - - return False diff --git a/game/missiongenerator/airsupportgenerator.py b/game/missiongenerator/airsupportgenerator.py deleted file mode 100644 index 468196d43..000000000 --- a/game/missiongenerator/airsupportgenerator.py +++ /dev/null @@ -1,210 +0,0 @@ -from __future__ import annotations - -import logging -from typing import List, TYPE_CHECKING, Tuple, Type - -from dcs.mission import Mission, StartType -from dcs.planes import IL_78M, KC130, KC135MPRS, KC_135, PlaneType -from dcs.task import ( - AWACS, - ActivateBeaconCommand, - MainTask, - Refueling, - SetImmortalCommand, - SetInvisibleCommand, -) -from dcs.unittype import UnitType - -from game.ato import FlightType -from game.callsigns import callsign_for_support_unit -from game.naming import namegen -from game.radio.radios import RadioRegistry -from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage -from game.utils import Heading -from .airconflictdescription import AirConflictDescription -from .missiondata import AwacsInfo, MissionData, TankerInfo - -if TYPE_CHECKING: - from game import Game - -TANKER_DISTANCE = 15000 -TANKER_ALT = 4572 -TANKER_HEADING_OFFSET = 45 - -AWACS_DISTANCE = 150000 -AWACS_ALT = 13000 - - -class AirSupportGenerator: - def __init__( - self, - mission: Mission, - conflict: AirConflictDescription, - game: Game, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - mission_data: MissionData, - ) -> None: - self.mission = mission - self.conflict = conflict - self.game = game - self.radio_registry = radio_registry - self.tacan_registry = tacan_registry - self.mission_data = mission_data - - @classmethod - def support_tasks(cls) -> List[Type[MainTask]]: - return [Refueling, AWACS] - - @staticmethod - def _get_tanker_params(unit_type: Type[UnitType]) -> Tuple[int, int]: - if unit_type is KC130: - return TANKER_ALT - 500, 596 - elif unit_type is KC_135: - return TANKER_ALT, 770 - elif unit_type is KC135MPRS: - return TANKER_ALT + 500, 596 - return TANKER_ALT, 574 - - def generate(self) -> None: - player_cp = ( - self.conflict.blue_cp - if self.conflict.blue_cp.captured - else self.conflict.red_cp - ) - - country = self.mission.country(self.game.blue.country_name) - - if not self.game.settings.disable_legacy_tanker: - fallback_tanker_number = 0 - - for i, tanker_unit_type in enumerate( - self.game.faction_for(player=True).tankers - ): - unit_type = tanker_unit_type.dcs_unit_type - if not issubclass(unit_type, PlaneType): - logging.warning(f"Refueling aircraft {unit_type} must be a plane") - continue - - # TODO: Make loiter altitude a property of the unit type. - alt, airspeed = self._get_tanker_params(tanker_unit_type.dcs_unit_type) - freq = self.radio_registry.alloc_uhf() - tacan = self.tacan_registry.alloc_for_band( - TacanBand.Y, TacanUsage.AirToAir - ) - tanker_heading = Heading.from_degrees( - self.conflict.red_cp.position.heading_between_point( - self.conflict.blue_cp.position - ) - + TANKER_HEADING_OFFSET * i - ) - tanker_position = player_cp.position.point_from_heading( - tanker_heading.degrees, TANKER_DISTANCE - ) - tanker_group = self.mission.refuel_flight( - country=country, - name=namegen.next_tanker_name(country, tanker_unit_type), - airport=None, - plane_type=unit_type, - position=tanker_position, - altitude=alt, - race_distance=58000, - frequency=freq.mhz, - start_type=StartType.Warm, - speed=airspeed, - tacanchannel=str(tacan), - ) - tanker_group.set_frequency(freq.mhz) - - callsign = callsign_for_support_unit(tanker_group) - tacan_callsign = { - "Texaco": "TEX", - "Arco": "ARC", - "Shell": "SHL", - }.get(callsign) - if tacan_callsign is None: - # The dict above is all the callsigns currently in the game, but - # non-Western countries don't use the callsigns and instead just - # use numbers. It's possible that none of those nations have - # TACAN compatible refueling aircraft, but fallback just in - # case. - tacan_callsign = f"TK{fallback_tanker_number}" - fallback_tanker_number += 1 - - if tanker_unit_type != IL_78M: - # Override PyDCS tacan channel. - tanker_group.points[0].tasks.pop() - tanker_group.points[0].tasks.append( - ActivateBeaconCommand( - tacan.number, - tacan.band.value, - tacan_callsign, - True, - tanker_group.units[0].id, - True, - ) - ) - - tanker_group.points[0].tasks.append(SetInvisibleCommand(True)) - tanker_group.points[0].tasks.append(SetImmortalCommand(True)) - - self.mission_data.tankers.append( - TankerInfo( - group_name=str(tanker_group.name), - callsign=callsign, - variant=tanker_unit_type.display_name, - freq=freq, - tacan=tacan, - start_time=None, - end_time=None, - blue=True, - ) - ) - - if not self.game.settings.disable_legacy_aewc: - possible_awacs = [ - a - for a in self.game.faction_for(player=True).aircrafts - if a.capable_of(FlightType.AEWC) - ] - - if not possible_awacs: - logging.warning("No AWACS for faction") - return - - awacs_unit = possible_awacs[0] - freq = self.radio_registry.alloc_uhf() - - unit_type = awacs_unit.dcs_unit_type - if not issubclass(unit_type, PlaneType): - logging.warning(f"AWACS aircraft {unit_type} must be a plane") - return - - awacs_flight = self.mission.awacs_flight( - country=country, - name=namegen.next_awacs_name(country), - plane_type=unit_type, - altitude=AWACS_ALT, - airport=None, - position=self.conflict.center.random_point_within( - AWACS_DISTANCE, AWACS_DISTANCE - ), - frequency=freq.mhz, - start_type=StartType.Warm, - ) - awacs_flight.set_frequency(freq.mhz) - - awacs_flight.points[0].tasks.append(SetInvisibleCommand(True)) - awacs_flight.points[0].tasks.append(SetImmortalCommand(True)) - - self.mission_data.awacs.append( - AwacsInfo( - group_name=str(awacs_flight.name), - callsign=callsign_for_support_unit(awacs_flight), - freq=freq, - depature_location=None, - start_time=None, - end_time=None, - blue=True, - ) - ) diff --git a/game/missiongenerator/briefinggenerator.py b/game/missiongenerator/briefinggenerator.py deleted file mode 100644 index e456d04ba..000000000 --- a/game/missiongenerator/briefinggenerator.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -Briefing generation logic -""" -from __future__ import annotations - -import os -from dataclasses import dataclass -from typing import Dict, List, TYPE_CHECKING - -from dcs.mission import Mission -from jinja2 import Environment, FileSystemLoader, select_autoescape - -from game.ato.flightwaypoint import FlightWaypoint -from game.ground_forces.combat_stance import CombatStance -from game.radio.radios import RadioFrequency -from game.runways import RunwayData -from game.theater import ControlPoint, FrontLine -from .aircraft.flightdata import FlightData -from .airsupportgenerator import AwacsInfo, TankerInfo -from .flotgenerator import JtacInfo - -if TYPE_CHECKING: - from game import Game - - -@dataclass -class CommInfo: - """Communications information for the kneeboard.""" - - name: str - freq: RadioFrequency - - -class FrontLineInfo: - def __init__(self, front_line: FrontLine): - self.front_line: FrontLine = front_line - self.player_base: ControlPoint = front_line.blue_cp - self.enemy_base: ControlPoint = front_line.red_cp - self.player_zero: bool = self.player_base.base.total_armor == 0 - self.enemy_zero: bool = self.enemy_base.base.total_armor == 0 - self.advantage: bool = ( - self.player_base.base.total_armor > self.enemy_base.base.total_armor - ) - self.stance: CombatStance = self.player_base.stances[self.enemy_base.id] - self.combat_stances = CombatStance - - -class MissionInfoGenerator: - """Base type for generators of mission information for the player. - - Examples of subtypes include briefing generators, kneeboard generators, etc. - """ - - def __init__(self, mission: Mission, game: Game) -> None: - self.mission = mission - self.game = game - self.awacs: List[AwacsInfo] = [] - self.comms: List[CommInfo] = [] - self.briefing_data: list[list[FlightData]] = [] - self.jtacs: List[JtacInfo] = [] - self.tankers: List[TankerInfo] = [] - self.frontlines: List[FrontLineInfo] = [] - self.dynamic_runways: List[RunwayData] = [] - - def add_awacs(self, awacs: AwacsInfo) -> None: - """Adds an AWACS/GCI to the mission. - - Args: - awacs: AWACS information. - """ - self.awacs.append(awacs) - - def add_comm(self, name: str, freq: RadioFrequency) -> None: - """Adds communications info to the mission. - - Args: - name: Name of the radio channel. - freq: Frequency of the radio channel. - """ - self.comms.append(CommInfo(name, freq)) - - def add_package_briefing_data(self, data: list[FlightData]) -> None: - """Adds flight info to the mission. - - Args: - data: The list of briefing data for each flight in a package. - """ - self.briefing_data.append(data) - - def add_jtac(self, jtac: JtacInfo) -> None: - """Adds a JTAC to the mission. - - Args: - jtac: JTAC information. - """ - self.jtacs.append(jtac) - - def add_tanker(self, tanker: TankerInfo) -> None: - """Adds a tanker to the mission. - - Args: - tanker: Tanker information. - """ - self.tankers.append(tanker) - - def add_frontline(self, frontline: FrontLineInfo) -> None: - """Adds a frontline to the briefing - - Arguments: - frontline: Frontline conflict information - """ - self.frontlines.append(frontline) - - def add_dynamic_runway(self, runway: RunwayData) -> None: - """Adds a dynamically generated runway to the briefing. - - Dynamic runways are any valid landing point that is a unit rather than a - map feature. These include carriers, ships with a helipad, and FARPs. - """ - self.dynamic_runways.append(runway) - - def generate(self) -> None: - """Generates the mission information.""" - raise NotImplementedError - - -def format_waypoint_time(waypoint: FlightWaypoint, depart_prefix: str) -> str: - if waypoint.tot is not None: - return f"{waypoint.tot.time()} " - elif waypoint.departure_time is not None: - return f"{depart_prefix} {waypoint.departure_time.time()} " - return "" - - -def format_intra_flight_channel(flight: FlightData) -> str: - frequency = flight.intra_flight_channel - channel = flight.channel_for(frequency) - if channel is None: - return str(frequency) - - channel_name = flight.aircraft_type.channel_name(channel.radio_id, channel.channel) - return f"{channel_name} ({frequency})" - - -class BriefingGenerator(MissionInfoGenerator): - def __init__(self, mission: Mission, game: Game): - super().__init__(mission, game) - self.allied_flights_by_departure: Dict[str, List[FlightData]] = {} - env = Environment( - loader=FileSystemLoader("resources/briefing/templates"), - autoescape=select_autoescape( - disabled_extensions=("",), - default_for_string=True, - default=True, - ), - trim_blocks=True, - lstrip_blocks=True, - ) - env.filters["waypoint_timing"] = format_waypoint_time - env.filters["intra_flight_channel"] = format_intra_flight_channel - self.template = env.get_template("briefingtemplate_EN.j2") - - def generate(self) -> None: - """Generate the mission briefing""" - self._generate_frontline_info() - self.generate_allied_flights_by_departure() - self.mission.set_description_text(self.template.render(vars(self))) - self.mission.add_picture_blue( - os.path.abspath("./resources/ui/splash_screen.png") - ) - - def _generate_frontline_info(self) -> None: - """Build FrontLineInfo objects from FrontLine type and append to briefing.""" - for front_line in self.game.theater.conflicts(): - self.add_frontline(FrontLineInfo(front_line)) - - # TODO: This should determine if runway is friendly through a method more robust than the existing string match - def generate_allied_flights_by_departure(self) -> None: - """Create iterable to display allied flights grouped by departure airfield.""" - for package in self.briefing_data: - for flight in package: - if not flight.client_units and flight.friendly: - name = flight.departure.airfield_name - if ( - name in self.allied_flights_by_departure - ): # where else can we get this? - self.allied_flights_by_departure[name].append(flight) - else: - self.allied_flights_by_departure[name] = [flight] diff --git a/game/missiongenerator/cargoshipgenerator.py b/game/missiongenerator/cargoshipgenerator.py deleted file mode 100644 index bf2f62504..000000000 --- a/game/missiongenerator/cargoshipgenerator.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -import itertools -from typing import TYPE_CHECKING - -from dcs import Mission -from dcs.unitgroup import ShipGroup - -from game.transfers import CargoShip -from game.unitmap import UnitMap -from game.utils import knots - -if TYPE_CHECKING: - from game import Game - - -class CargoShipGenerator: - def __init__(self, mission: Mission, game: Game, unit_map: UnitMap) -> None: - self.mission = mission - self.game = game - self.unit_map = unit_map - self.count = itertools.count() - - def generate(self) -> None: - # Reset the count to make generation deterministic. - for coalition in self.game.coalitions: - for ship in coalition.transfers.cargo_ships: - self.generate_cargo_ship(ship) - - def generate_cargo_ship(self, ship: CargoShip) -> ShipGroup: - coalition = self.game.coalition_for(ship.player_owned) - country = self.mission.country(coalition.country_name) - waypoints = ship.route - group = self.mission.ship_group( - country, - ship.name, - coalition.faction.cargo_ship.dcs_unit_type, - position=waypoints[0], - group_size=1, - ) - for waypoint in waypoints[1:]: - # 12 knots is very slow but it's also nearly the max allowed by DCS for this - # type of ship. - group.add_waypoint(waypoint, speed=knots(12).kph) - self.unit_map.add_cargo_ship(group, ship) - return group diff --git a/game/missiongenerator/convoygenerator.py b/game/missiongenerator/convoygenerator.py deleted file mode 100644 index a1fe60b7d..000000000 --- a/game/missiongenerator/convoygenerator.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -import itertools -from typing import TYPE_CHECKING - -from dcs import Mission -from dcs.mapping import Point -from dcs.point import PointAction -from dcs.unit import Vehicle -from dcs.unitgroup import VehicleGroup - -from game.dcs.groundunittype import GroundUnitType -from game.transfers import Convoy -from game.unitmap import UnitMap -from game.utils import kph - -if TYPE_CHECKING: - from game import Game - - -class ConvoyGenerator: - def __init__(self, mission: Mission, game: Game, unit_map: UnitMap) -> None: - self.mission = mission - self.game = game - self.unit_map = unit_map - self.count = itertools.count() - - def generate(self) -> None: - # Reset the count to make generation deterministic. - for coalition in self.game.coalitions: - for convoy in coalition.transfers.convoys: - self.generate_convoy(convoy) - - def generate_convoy(self, convoy: Convoy) -> VehicleGroup: - group = self._create_mixed_unit_group( - convoy.name, - convoy.route_start, - convoy.units, - convoy.player_owned, - ) - - if self.game.settings.convoys_travel_full_distance: - end_point = convoy.route_end - else: - # convoys_travel_full_distance is disabled, so have the convoy only move the - # first segment on the route. This option aims to remove long routes for - # ground vehicles between control points, since the CPU load for pathfinding - # long routes on DCS can be pretty heavy. - route = convoy.origin.convoy_route_to(convoy.destination) - - # Select the first route segment from the origin towards the destination so - # the convoy spawns at the origin CP. This allows the convoy to be targeted - # by BAI flights and starts it within the protection umbrella of the CP. - end_point = route[1] - - group.add_waypoint( - end_point, - speed=kph(40).kph, - move_formation=PointAction.OnRoad, - ) - - self.make_drivable(group) - self.unit_map.add_convoy_units(group, convoy) - return group - - def _create_mixed_unit_group( - self, - name: str, - position: Point, - units: dict[GroundUnitType, int], - for_player: bool, - ) -> VehicleGroup: - country = self.mission.country(self.game.coalition_for(for_player).country_name) - - unit_types = list(units.items()) - main_unit_type, main_unit_count = unit_types[0] - - group = self.mission.vehicle_group( - country, - name, - main_unit_type.dcs_unit_type, - position=position, - group_size=main_unit_count, - move_formation=PointAction.OnRoad, - ) - - unit_name_counter = itertools.count(main_unit_count + 1) - # pydcs spreads units out by 20 in the Y axis by default. Pick up where it left - # off. - y = itertools.count(position.y + main_unit_count * 20, 20) - for unit_type, count in unit_types[1:]: - for i in range(count): - v = self.mission.vehicle( - f"{name} Unit #{next(unit_name_counter)}", unit_type.dcs_unit_type - ) - v.position.x = position.x - v.position.y = next(y) - v.heading = 0 - group.add_unit(v) - - return group - - @staticmethod - def make_drivable(group: VehicleGroup) -> None: - for v in group.units: - if isinstance(v, Vehicle): - v.player_can_drive = True diff --git a/game/missiongenerator/drawingsgenerator.py b/game/missiongenerator/drawingsgenerator.py deleted file mode 100644 index 19a2f235f..000000000 --- a/game/missiongenerator/drawingsgenerator.py +++ /dev/null @@ -1,106 +0,0 @@ -from dcs import Point -from dcs.drawing import LineStyle, Rgba -from dcs.drawing.drawings import StandardLayer -from dcs.mission import Mission - -from game import Game -from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, -) - -# Misc config settings for objects drawn in ME mission file (and F10 map) -FRONTLINE_COLORS = Rgba(255, 0, 0, 255) -WHITE = Rgba(255, 255, 255, 255) -CP_RED = Rgba(255, 0, 0, 80) -CP_BLUE = Rgba(0, 0, 255, 80) -CP_CIRCLE_RADIUS = 2500 -BLUE_PATH_COLOR = Rgba(0, 0, 255, 100) -RED_PATH_COLOR = Rgba(255, 0, 0, 100) -ACTIVE_PATH_COLOR = Rgba(255, 80, 80, 100) - - -class DrawingsGenerator: - """ - Generate drawn objects for the F10 map and mission editor - """ - - def __init__(self, mission: Mission, game: Game) -> None: - self.mission = mission - self.game = game - self.player_layer = self.mission.drawings.get_layer(StandardLayer.Blue) - - def generate_cps_markers(self) -> None: - """ - Generate cps as circles - """ - for cp in self.game.theater.controlpoints: - if cp.captured: - color = CP_BLUE - else: - color = CP_RED - shape = self.player_layer.add_circle( - cp.position, - CP_CIRCLE_RADIUS, - line_thickness=2, - color=WHITE, - fill=color, - line_style=LineStyle.Dot, - ) - shape.name = cp.name - - def generate_routes(self) -> None: - """ - Generate routes drawing between cps - """ - seen = set() - for cp in self.game.theater.controlpoints: - seen.add(cp) - for destination, convoy_route in cp.convoy_routes.items(): - if destination in seen: - continue - else: - # Determine path color - if cp.captured and destination.captured: - color = BLUE_PATH_COLOR - elif not cp.captured and not destination.captured: - color = RED_PATH_COLOR - else: - color = ACTIVE_PATH_COLOR - - # Add shape to layer - shape = self.player_layer.add_line_segments( - cp.position, - [Point(0, 0, self.game.theater.terrain)] - + [p - cp.position for p in convoy_route] - + [destination.position - cp.position], - line_thickness=6, - color=color, - line_style=LineStyle.Solid, - ) - shape.name = "path from " + cp.name + " to " + destination.name - - def generate_frontlines_drawing(self) -> None: - """ - Generate a frontline "line" for each active frontline - """ - for front_line in self.game.theater.conflicts(): - bounds = FrontLineConflictDescription.frontline_bounds( - front_line, self.game.theater - ) - - end_point = bounds.left_position.point_from_heading( - bounds.heading_from_left_to_right.degrees, bounds.length - ) - shape = self.player_layer.add_line_segment( - bounds.left_position, - end_point - bounds.left_position, - line_thickness=16, - color=FRONTLINE_COLORS, - line_style=LineStyle.Triangle, - ) - shape.name = front_line.name - - def generate(self) -> None: - self.generate_frontlines_drawing() - self.generate_routes() - self.generate_cps_markers() diff --git a/game/missiongenerator/environmentgenerator.py b/game/missiongenerator/environmentgenerator.py deleted file mode 100644 index 9fbae5e47..000000000 --- a/game/missiongenerator/environmentgenerator.py +++ /dev/null @@ -1,51 +0,0 @@ -from datetime import datetime -from typing import Optional - -from dcs.mission import Mission - -from game.weather.atmosphericconditions import AtmosphericConditions -from game.weather.clouds import Clouds -from game.weather.conditions import Conditions -from game.weather.fog import Fog -from game.weather.wind import WindConditions - - -class EnvironmentGenerator: - def __init__( - self, mission: Mission, conditions: Conditions, time: datetime - ) -> None: - self.mission = mission - self.conditions = conditions - self.time = time - - def set_atmospheric(self, atmospheric: AtmosphericConditions) -> None: - self.mission.weather.qnh = atmospheric.qnh.mm_hg - self.mission.weather.season_temperature = atmospheric.temperature_celsius - self.mission.weather.turbulence_at_ground = int(atmospheric.turbulence_per_10cm) - - def set_clouds(self, clouds: Optional[Clouds]) -> None: - if clouds is None: - return - self.mission.weather.clouds_base = clouds.base - self.mission.weather.clouds_thickness = clouds.thickness - self.mission.weather.clouds_density = clouds.density - self.mission.weather.clouds_iprecptns = clouds.precipitation - self.mission.weather.clouds_preset = clouds.preset - - def set_fog(self, fog: Optional[Fog]) -> None: - if fog is None: - return - self.mission.weather.fog_visibility = int(fog.visibility.meters) - self.mission.weather.fog_thickness = fog.thickness - - def set_wind(self, wind: WindConditions) -> None: - self.mission.weather.wind_at_ground = wind.at_0m - self.mission.weather.wind_at_2000 = wind.at_2000m - self.mission.weather.wind_at_8000 = wind.at_8000m - - def generate(self) -> None: - self.mission.start_time = self.time - self.set_atmospheric(self.conditions.weather.atmospheric) - self.set_clouds(self.conditions.weather.clouds) - self.set_fog(self.conditions.weather.fog) - self.set_wind(self.conditions.weather.wind) diff --git a/game/missiongenerator/flotgenerator.py b/game/missiongenerator/flotgenerator.py deleted file mode 100644 index 3be5fc4c1..000000000 --- a/game/missiongenerator/flotgenerator.py +++ /dev/null @@ -1,778 +0,0 @@ -from __future__ import annotations - -import math -import random -from typing import List, Optional, TYPE_CHECKING, Tuple - -from dcs import Mission -from dcs.action import AITaskPush -from dcs.condition import GroupLifeLess, Or, TimeAfter, UnitDamaged -from dcs.country import Country -from dcs.mapping import Point, Vector2 -from dcs.point import PointAction -from dcs.task import ( - AFAC, - AttackGroup, - ControlledTask, - EPLRS, - FAC, - FireAtPoint, - GoToWaypoint, - Hold, - OrbitAction, - SetImmortalCommand, - SetInvisibleCommand, -) -from dcs.triggers import Event, TriggerOnce -from dcs.unit import Skill, Vehicle -from dcs.unitgroup import VehicleGroup - -from game.callsigns import callsign_for_support_unit -from game.data.units import UnitClass -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.ground_forces.ai_ground_planner import ( - CombatGroup, - CombatGroupRole, - DISTANCE_FROM_FRONTLINE, -) -from game.ground_forces.combat_stance import CombatStance -from game.naming import namegen -from game.radio.radios import RadioRegistry -from game.theater.controlpoint import ControlPoint -from game.unitmap import UnitMap -from game.utils import Heading -from .frontlineconflictdescription import FrontLineConflictDescription -from .missiondata import JtacInfo, MissionData - -if TYPE_CHECKING: - from game import Game - -SPREAD_DISTANCE_FACTOR = 0.1, 0.3 -SPREAD_DISTANCE_SIZE_FACTOR = 0.1 - -FRONTLINE_CAS_FIGHTS_COUNT = 16, 24 -FRONTLINE_CAS_GROUP_MIN = 1, 2 -FRONTLINE_CAS_PADDING = 12000 - -RETREAT_DISTANCE = 20000 -BREAKTHROUGH_OFFENSIVE_DISTANCE = 35000 -AGGRESIVE_MOVE_DISTANCE = 16000 - -FIGHT_DISTANCE = 3500 - -RANDOM_OFFSET_ATTACK = 250 - -INFANTRY_GROUP_SIZE = 5 - - -class FlotGenerator: - def __init__( - self, - mission: Mission, - conflict: FrontLineConflictDescription, - game: Game, - player_planned_combat_groups: List[CombatGroup], - enemy_planned_combat_groups: List[CombatGroup], - player_stance: CombatStance, - enemy_stance: CombatStance, - unit_map: UnitMap, - radio_registry: RadioRegistry, - mission_data: MissionData, - ) -> None: - self.mission = mission - self.conflict = conflict - self.enemy_planned_combat_groups = enemy_planned_combat_groups - self.player_planned_combat_groups = player_planned_combat_groups - self.player_stance = player_stance - self.enemy_stance = enemy_stance - self.game = game - self.unit_map = unit_map - self.radio_registry = radio_registry - self.mission_data = mission_data - - def generate(self) -> None: - position = FrontLineConflictDescription.frontline_position( - self.conflict.front_line, self.game.theater - ) - - # Create player groups at random position - player_groups = self._generate_groups( - self.player_planned_combat_groups, is_player=True - ) - - # Create enemy groups at random position - enemy_groups = self._generate_groups( - self.enemy_planned_combat_groups, is_player=False - ) - - # TODO: Differentiate AirConflict and GroundConflict classes. - if self.conflict.heading is None: - raise RuntimeError( - "Cannot generate ground units for non-ground conflict. Ground unit " - "conflicts cannot have the heading `None`." - ) - - # Plan combat actions for groups - self.plan_action_for_groups( - self.player_stance, - player_groups, - enemy_groups, - self.conflict.heading.right, - self.conflict.blue_cp, - self.conflict.red_cp, - ) - self.plan_action_for_groups( - self.enemy_stance, - enemy_groups, - player_groups, - self.conflict.heading.left, - self.conflict.red_cp, - self.conflict.blue_cp, - ) - - # Add JTAC - if self.game.blue.faction.has_jtac: - freq = self.radio_registry.alloc_uhf() - # If the option fc3LaserCode is enabled, force all JTAC - # laser codes to 1113 to allow lasing for Su-25 Frogfoots and A-10A Warthogs. - # Otherwise use 1688 for the first JTAC, 1687 for the second etc. - if self.game.lua_plugin_manager.is_option_enabled("ctld", "fc3LaserCode"): - code = self.game.laser_code_registry.fc3_code - else: - code = self.conflict.front_line.laser_code - - utype = self.game.blue.faction.jtac_unit - if utype is None: - utype = AircraftType.named("MQ-9 Reaper") - - jtac = self.mission.flight_group( - country=self.mission.country(self.game.blue.country_name), - name=namegen.next_jtac_name(), - aircraft_type=utype.dcs_unit_type, - position=position[0], - airport=None, - altitude=5000, - maintask=AFAC, - ) - jtac.points[0].tasks.append( - FAC( - callsign=len(self.mission_data.jtacs) + 1, - frequency=int(freq.mhz), - modulation=freq.modulation, - ) - ) - jtac.points[0].tasks.append(SetInvisibleCommand(True)) - jtac.points[0].tasks.append(SetImmortalCommand(True)) - jtac.points[0].tasks.append( - OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle) - ) - frontline = ( - f"Frontline {self.conflict.blue_cp.name}/{self.conflict.red_cp.name}" - ) - # Note: Will need to change if we ever add ground based JTAC. - callsign = callsign_for_support_unit(jtac) - self.mission_data.jtacs.append( - JtacInfo( - group_name=jtac.name, - unit_name=jtac.units[0].name, - callsign=callsign, - region=frontline, - code=str(code), - blue=True, - freq=freq, - ) - ) - - def gen_infantry_group_for_group( - self, - group: VehicleGroup, - is_player: bool, - side: Country, - forward_heading: Heading, - ) -> None: - infantry_position = self.conflict.find_ground_position( - group.points[0].position.random_point_within(250, 50), - 500, - forward_heading, - self.conflict.theater, - ) - - faction = self.game.faction_for(is_player) - - # Disable infantry unit gen if disabled - if not self.game.settings.perf_infantry: - if self.game.settings.manpads: - # 50% of armored units protected by manpad - if random.choice([True, False]): - manpads = list(faction.infantry_with_class(UnitClass.MANPAD)) - if manpads: - u = random.choices( - manpads, weights=[m.spawn_weight for m in manpads] - )[0] - infantry_group = self.mission.vehicle_group( - side, - namegen.next_infantry_name(side, u), - u.dcs_unit_type, - position=infantry_position, - group_size=1, - heading=forward_heading.degrees, - move_formation=PointAction.OffRoad, - ) - infantry_group.hidden_on_mfd = True - return - - possible_infantry_units = set(faction.infantry_with_class(UnitClass.INFANTRY)) - if self.game.settings.manpads: - possible_infantry_units |= set( - faction.infantry_with_class(UnitClass.MANPAD) - ) - if not possible_infantry_units: - return - - infantry_choices = list(possible_infantry_units) - units = random.choices( - infantry_choices, - weights=[u.spawn_weight for u in infantry_choices], - k=INFANTRY_GROUP_SIZE, - ) - infantry_group = self.mission.vehicle_group( - side, - namegen.next_infantry_name(side, units[0]), - units[0].dcs_unit_type, - position=infantry_position, - group_size=1, - heading=forward_heading.degrees, - move_formation=PointAction.OffRoad, - ) - infantry_group.hidden_on_mfd = True - - for unit in units[1:]: - position = infantry_position.random_point_within(55, 5) - infantry_group = self.mission.vehicle_group( - side, - namegen.next_infantry_name(side, unit), - unit.dcs_unit_type, - position=position, - group_size=1, - heading=forward_heading.degrees, - move_formation=PointAction.OffRoad, - ) - infantry_group.hidden_on_mfd = True - - def _set_reform_waypoint( - self, dcs_group: VehicleGroup, forward_heading: Heading - ) -> None: - """Setting a waypoint close to the spawn position allows the group to reform gracefully - rather than spin - """ - reform_point = dcs_group.position.point_from_heading( - forward_heading.degrees, 50 - ) - dcs_group.add_waypoint(reform_point) - - def _plan_artillery_action( - self, - stance: CombatStance, - gen_group: CombatGroup, - dcs_group: VehicleGroup, - forward_heading: Heading, - target: Point, - ) -> bool: - """ - Handles adding the DCS tasks for artillery groups for all combat stances. - Returns True if tasking was added, returns False if the stance was not a combat stance. - """ - self._set_reform_waypoint(dcs_group, forward_heading) - if stance != CombatStance.RETREAT: - hold_task = Hold() - hold_task.number = 1 - dcs_group.add_trigger_action(hold_task) - - # Artillery strike random start - artillery_trigger = TriggerOnce( - Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id) - ) - artillery_trigger.add_condition(TimeAfter(seconds=random.randint(1, 45) * 60)) - # TODO: Update to fire at group instead of point - fire_task = FireAtPoint(target, gen_group.size * 10, 100) - fire_task.number = 2 if stance != CombatStance.RETREAT else 1 - dcs_group.add_trigger_action(fire_task) - artillery_trigger.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks))) - self.mission.triggerrules.triggers.append(artillery_trigger) - - # Artillery will fall back when under attack - if stance != CombatStance.RETREAT: - # Hold position - dcs_group.points[1].tasks.append(Hold()) - retreat = self.find_retreat_point( - dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 3) - ) - dcs_group.add_waypoint( - dcs_group.position.point_from_heading(forward_heading.degrees, 1), - PointAction.OffRoad, - ) - dcs_group.points[2].tasks.append(Hold()) - dcs_group.add_waypoint(retreat, PointAction.OffRoad) - - artillery_fallback = TriggerOnce( - Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id) - ) - for i, u in enumerate(dcs_group.units): - artillery_fallback.add_condition(UnitDamaged(u.id)) - if i < len(dcs_group.units) - 1: - artillery_fallback.add_condition(Or()) - - hold_2 = Hold() - hold_2.number = 3 - dcs_group.add_trigger_action(hold_2) - - retreat_task = GoToWaypoint(to_index=3) - retreat_task.number = 4 - dcs_group.add_trigger_action(retreat_task) - - artillery_fallback.add_action( - AITaskPush(dcs_group.id, len(dcs_group.tasks)) - ) - self.mission.triggerrules.triggers.append(artillery_fallback) - - for u in dcs_group.units: - u.heading = (forward_heading + Heading.random(-5, 5)).degrees - return True - return False - - def _plan_tank_ifv_action( - self, - stance: CombatStance, - enemy_groups: List[Tuple[VehicleGroup, CombatGroup]], - dcs_group: VehicleGroup, - forward_heading: Heading, - to_cp: ControlPoint, - ) -> bool: - """ - Handles adding the DCS tasks for tank and IFV groups for all combat stances. - Returns True if tasking was added, returns False if the stance was not a combat stance. - """ - self._set_reform_waypoint(dcs_group, forward_heading) - if stance == CombatStance.AGGRESSIVE: - # Attack nearest enemy if any - # Then move forward OR Attack enemy base if it is not too far away - target = self.find_nearest_enemy_group(dcs_group, enemy_groups) - if target is not None: - rand_offset = Vector2( - random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), - random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), - ) - target_point = self.conflict.theater.nearest_land_pos( - target.points[0].position + rand_offset - ) - dcs_group.add_waypoint(target_point) - dcs_group.points[2].tasks.append(AttackGroup(target.id)) - - if ( - to_cp.position.distance_to_point(dcs_group.points[0].position) - <= AGGRESIVE_MOVE_DISTANCE - ): - attack_point = self.conflict.theater.nearest_land_pos( - to_cp.position.random_point_within(500, 0) - ) - else: - # We use an offset heading here because DCS doesn't always - # force vehicles to move if there's no heading change. - offset_heading = forward_heading - Heading.from_degrees(2) - attack_point = self.find_offensive_point( - dcs_group, offset_heading, AGGRESIVE_MOVE_DISTANCE - ) - dcs_group.add_waypoint(attack_point, PointAction.OffRoad) - elif stance == CombatStance.BREAKTHROUGH: - # In breakthrough mode, the units will move forward - # If the enemy base is close enough, the units will attack the base - if ( - to_cp.position.distance_to_point(dcs_group.points[0].position) - <= BREAKTHROUGH_OFFENSIVE_DISTANCE - ): - attack_point = self.conflict.theater.nearest_land_pos( - to_cp.position.random_point_within(500, 0) - ) - else: - # We use an offset heading here because DCS doesn't always - # force vehicles to move if there's no heading change. - offset_heading = forward_heading - Heading.from_degrees(1) - attack_point = self.find_offensive_point( - dcs_group, offset_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE - ) - dcs_group.add_waypoint(attack_point, PointAction.OffRoad) - elif stance == CombatStance.ELIMINATION: - # In elimination mode, the units focus on destroying as much enemy groups as possible - targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3) - for i, target in enumerate(targets, start=1): - rand_offset = Vector2( - random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), - random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), - ) - target_point = self.conflict.theater.nearest_land_pos( - target.points[0].position + rand_offset - ) - dcs_group.add_waypoint(target_point, PointAction.OffRoad) - dcs_group.points[i + 1].tasks.append(AttackGroup(target.id)) - if ( - to_cp.position.distance_to_point(dcs_group.points[0].position) - <= AGGRESIVE_MOVE_DISTANCE - ): - attack_point = self.conflict.theater.nearest_land_pos( - to_cp.position.random_point_within(500, 0) - ) - dcs_group.add_waypoint(attack_point) - - if stance != CombatStance.RETREAT: - self.add_morale_trigger(dcs_group, forward_heading) - return True - return False - - def _plan_apc_atgm_action( - self, - stance: CombatStance, - dcs_group: VehicleGroup, - forward_heading: Heading, - to_cp: ControlPoint, - ) -> bool: - """ - Handles adding the DCS tasks for APC and ATGM groups for all combat stances. - Returns True if tasking was added, returns False if the stance was not a combat stance. - """ - self._set_reform_waypoint(dcs_group, forward_heading) - if stance in [ - CombatStance.AGGRESSIVE, - CombatStance.BREAKTHROUGH, - CombatStance.ELIMINATION, - ]: - # APC & ATGM will never move too much forward, but will follow along any offensive - if ( - to_cp.position.distance_to_point(dcs_group.points[0].position) - <= AGGRESIVE_MOVE_DISTANCE - ): - attack_point = self.conflict.theater.nearest_land_pos( - to_cp.position.random_point_within(500, 0) - ) - else: - attack_point = self.find_offensive_point( - dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE - ) - dcs_group.add_waypoint(attack_point, PointAction.OffRoad) - - if stance != CombatStance.RETREAT: - self.add_morale_trigger(dcs_group, forward_heading) - return True - return False - - def plan_action_for_groups( - self, - stance: CombatStance, - ally_groups: List[Tuple[VehicleGroup, CombatGroup]], - enemy_groups: List[Tuple[VehicleGroup, CombatGroup]], - forward_heading: Heading, - from_cp: ControlPoint, - to_cp: ControlPoint, - ) -> None: - if not self.game.settings.perf_moving_units: - return - - for dcs_group, group in ally_groups: - if group.unit_type.eplrs_capable: - dcs_group.points[0].tasks.append(EPLRS(dcs_group.id)) - - if group.role == CombatGroupRole.ARTILLERY: - if self.game.settings.perf_artillery: - target = self.get_artillery_target_in_range( - dcs_group, group, enemy_groups - ) - if target is not None: - self._plan_artillery_action( - stance, group, dcs_group, forward_heading, target - ) - - elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]: - self._plan_tank_ifv_action( - stance, enemy_groups, dcs_group, forward_heading, to_cp - ) - - elif group.role in [CombatGroupRole.APC, CombatGroupRole.ATGM]: - self._plan_apc_atgm_action(stance, dcs_group, forward_heading, to_cp) - - if stance == CombatStance.RETREAT: - # In retreat mode, the units will fall back - # If the ally base is close enough, the units will even regroup there - if ( - from_cp.position.distance_to_point(dcs_group.points[0].position) - <= RETREAT_DISTANCE - ): - retreat_point = from_cp.position.random_point_within(500, 250) - else: - retreat_point = self.find_retreat_point(dcs_group, forward_heading) - reposition_point = retreat_point.point_from_heading( - forward_heading.degrees, 10 - ) # Another point to make the unit face the enemy - dcs_group.add_waypoint(retreat_point, PointAction.OffRoad) - dcs_group.add_waypoint(reposition_point, PointAction.OffRoad) - - def add_morale_trigger( - self, dcs_group: VehicleGroup, forward_heading: Heading - ) -> None: - """ - This add a trigger to manage units fleeing whenever their group is hit hard, or being engaged by CAS - """ - - if len(dcs_group.units) == 1: - return - - # Units should hold position on last waypoint - dcs_group.points[len(dcs_group.points) - 1].tasks.append(Hold()) - - # Force unit heading - for unit in dcs_group.units: - unit.heading = forward_heading.degrees - dcs_group.manualHeading = True - - # We add a new retreat waypoint - dcs_group.add_waypoint( - self.find_retreat_point( - dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 8) - ), - PointAction.OffRoad, - ) - - # Fallback task - task = ControlledTask(GoToWaypoint(to_index=len(dcs_group.points))) - task.enabled = False - dcs_group.add_trigger_action(Hold()) - dcs_group.add_trigger_action(task) - - # Create trigger - fallback = TriggerOnce(Event.NoEvent, "Morale manager #" + str(dcs_group.id)) - - # Usually more than 50% casualties = RETREAT - fallback.add_condition(GroupLifeLess(dcs_group.id, random.randint(51, 76))) - - # Do retreat to the configured retreat waypoint - fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks))) - - self.mission.triggerrules.triggers.append(fallback) - - def find_retreat_point( - self, - dcs_group: VehicleGroup, - frontline_heading: Heading, - distance: int = RETREAT_DISTANCE, - ) -> Point: - """ - Find a point to retreat to - :param dcs_group: DCS mission group we are searching a retreat point for - :param frontline_heading: Heading of the frontline - :return: dcs.mapping.Point object with the desired position - """ - desired_point = dcs_group.points[0].position.point_from_heading( - frontline_heading.opposite.degrees, distance - ) - if self.conflict.theater.is_on_land(desired_point): - return desired_point - return self.conflict.theater.nearest_land_pos(desired_point) - - def find_offensive_point( - self, dcs_group: VehicleGroup, frontline_heading: Heading, distance: int - ) -> Point: - """ - Find a point to attack - :param dcs_group: DCS mission group we are searching an attack point for - :param frontline_heading: Heading of the frontline - :param distance: Distance of the offensive (how far unit should move) - :return: dcs.mapping.Point object with the desired position - """ - desired_point = dcs_group.points[0].position.point_from_heading( - frontline_heading.degrees, distance - ) - if self.conflict.theater.is_on_land(desired_point): - return desired_point - return self.conflict.theater.nearest_land_pos(desired_point) - - @staticmethod - def find_n_nearest_enemy_groups( - player_group: VehicleGroup, - enemy_groups: List[Tuple[VehicleGroup, CombatGroup]], - n: int, - ) -> List[VehicleGroup]: - """ - Return the nearest enemy group for the player group - @param group Group for which we should find the nearest ennemies - @param enemy_groups Potential enemy groups - @param n number of nearby groups to take - """ - targets = [] # type: List[VehicleGroup] - sorted_list = sorted( - enemy_groups, - key=lambda group: player_group.points[0].position.distance_to_point( - group[0].points[0].position - ), - ) - for i in range(n): - # TODO: Is this supposed to return no groups if enemy_groups is less than n? - if len(sorted_list) <= i: - break - else: - targets.append(sorted_list[i][0]) - return targets - - @staticmethod - def find_nearest_enemy_group( - player_group: VehicleGroup, enemy_groups: List[Tuple[VehicleGroup, CombatGroup]] - ) -> Optional[VehicleGroup]: - """ - Search the enemy groups for a potential target suitable to armored assault - @param group Group for which we should find the nearest ennemy - @param enemy_groups Potential enemy groups - """ - min_distance = math.inf - target = None - for dcs_group, _ in enemy_groups: - dist = player_group.points[0].position.distance_to_point( - dcs_group.points[0].position - ) - if dist < min_distance: - min_distance = dist - target = dcs_group - return target - - @staticmethod - def get_artillery_target_in_range( - dcs_group: VehicleGroup, - group: CombatGroup, - enemy_groups: List[Tuple[VehicleGroup, CombatGroup]], - ) -> Optional[Point]: - """ - Search the enemy groups for a potential target suitable to an artillery unit - """ - # TODO: Update to return a list of groups instead of a single point - rng = getattr(group.unit_type.dcs_unit_type, "threat_range", 0) - if not enemy_groups: - return None - for _ in range(10): - potential_target = random.choice(enemy_groups)[0] - distance_to_target = dcs_group.points[0].position.distance_to_point( - potential_target.points[0].position - ) - if distance_to_target < rng: - return potential_target.points[0].position - return None - - @staticmethod - def get_artilery_group_distance_from_frontline(group: CombatGroup) -> int: - """ - For artilery group, decide the distance from frontline with the range of the unit - """ - rg = group.unit_type.dcs_unit_type.threat_range - 7500 - if rg > DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]: - rg = random.randint( - DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][0], - DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1], - ) - elif rg < DISTANCE_FROM_FRONTLINE[CombatGroupRole.ARTILLERY][1]: - rg = random.randint( - DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][0], - DISTANCE_FROM_FRONTLINE[CombatGroupRole.TANK][1], - ) - return rg - - def get_valid_position_for_group( - self, distance_from_frontline: int, spawn_heading: Heading - ) -> Point: - assert self.conflict.heading is not None - assert self.conflict.size is not None - shifted = self.conflict.position.point_from_heading( - self.conflict.heading.degrees, - random.randint(0, self.conflict.size), - ) - desired_point = shifted.point_from_heading( - spawn_heading.degrees, distance_from_frontline - ) - return FrontLineConflictDescription.find_ground_position( - desired_point, - self.conflict.size, - self.conflict.heading, - self.conflict.theater, - ) - - def _generate_groups( - self, groups: list[CombatGroup], is_player: bool - ) -> List[Tuple[VehicleGroup, CombatGroup]]: - """Finds valid positions for planned groups and generates a pydcs group for them""" - positioned_groups = [] - assert self.conflict.heading is not None - spawn_heading = ( - self.conflict.heading.left if is_player else self.conflict.heading.right - ) - country = self.game.coalition_for(is_player).country_name - for group in groups: - if group.role == CombatGroupRole.ARTILLERY: - distance_from_frontline = ( - self.get_artilery_group_distance_from_frontline(group) - ) - else: - distance_from_frontline = random.randint( - DISTANCE_FROM_FRONTLINE[group.role][0], - DISTANCE_FROM_FRONTLINE[group.role][1], - ) - - final_position = self.get_valid_position_for_group( - distance_from_frontline, spawn_heading - ) - - g = self._generate_group( - is_player, - self.mission.country(country), - group.unit_type, - group.size, - final_position, - heading=spawn_heading.opposite, - ) - if is_player: - g.set_skill(Skill(self.game.settings.player_skill)) - else: - g.set_skill(Skill(self.game.settings.enemy_vehicle_skill)) - positioned_groups.append((g, group)) - - if group.role in [CombatGroupRole.APC, CombatGroupRole.IFV]: - self.gen_infantry_group_for_group( - g, - is_player, - self.mission.country(country), - spawn_heading.opposite, - ) - - return positioned_groups - - def _generate_group( - self, - player: bool, - side: Country, - unit_type: GroundUnitType, - count: int, - at: Point, - heading: Heading, - ) -> VehicleGroup: - cp = self.conflict.front_line.control_point_friendly_to(player) - group = self.mission.vehicle_group( - side, - namegen.next_unit_name(side, unit_type), - unit_type.dcs_unit_type, - position=at, - group_size=count, - heading=heading.degrees, - ) - group.hidden_on_mfd = True - - self.unit_map.add_front_line_units(group, cp, unit_type) - - for c in range(count): - vehicle: Vehicle = group.units[c] - vehicle.player_can_drive = True - - return group diff --git a/game/missiongenerator/forcedoptionsgenerator.py b/game/missiongenerator/forcedoptionsgenerator.py deleted file mode 100644 index 017331db1..000000000 --- a/game/missiongenerator/forcedoptionsgenerator.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from dcs.forcedoptions import ForcedOptions -from dcs.mission import Mission - -if TYPE_CHECKING: - from game.game import Game - - -class ForcedOptionsGenerator: - def __init__(self, mission: Mission, game: Game) -> None: - self.mission = mission - self.game = game - - def _set_options_view(self) -> None: - self.mission.forced_options.options_view = ( - self.game.settings.map_coalition_visibility - ) - - def _set_external_views(self) -> None: - if not self.game.settings.external_views_allowed: - self.mission.forced_options.external_views = ( - self.game.settings.external_views_allowed - ) - - def _set_easy_communication(self) -> None: - self.mission.forced_options.easy_communication = ( - self.game.settings.easy_communication - ) - - def _set_labels(self) -> None: - # TODO: Fix settings to use the real type. - # TODO: Allow forcing "full" and have default do nothing. - if self.game.settings.labels == "Abbreviated": - self.mission.forced_options.labels = ForcedOptions.Labels.Abbreviate - elif self.game.settings.labels == "Dot Only": - self.mission.forced_options.labels = ForcedOptions.Labels.DotOnly - elif self.game.settings.labels == "Neutral Dot": - self.mission.forced_options.labels = ForcedOptions.Labels.NeutralDot - elif self.game.settings.labels == "Off": - self.mission.forced_options.labels = ForcedOptions.Labels.None_ - - def _set_unrestricted_satnav(self) -> None: - blue = self.game.blue.faction - red = self.game.red.faction - if blue.unrestricted_satnav or red.unrestricted_satnav: - self.mission.forced_options.unrestricted_satnav = True - - def _set_battle_damage_assessment(self) -> None: - self.mission.forced_options.battle_damage_assessment = ( - self.game.settings.battle_damage_assessment - ) - - def generate(self) -> None: - self._set_options_view() - self._set_external_views() - self._set_easy_communication() - self._set_labels() - self._set_unrestricted_satnav() - self._set_battle_damage_assessment() diff --git a/game/missiongenerator/frontlineconflictdescription.py b/game/missiongenerator/frontlineconflictdescription.py deleted file mode 100644 index 1df380187..000000000 --- a/game/missiongenerator/frontlineconflictdescription.py +++ /dev/null @@ -1,169 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from functools import cached_property -from typing import Optional, Tuple - -from dcs.mapping import Point -from shapely.geometry import LineString, Point as ShapelyPoint -from shapely.ops import nearest_points - -from game.theater.conflicttheater import ConflictTheater, FrontLine -from game.theater.controlpoint import ControlPoint -from game.utils import Heading, dcs_to_shapely_point - -FRONTLINE_LENGTH = 80000 - - -@dataclass(frozen=True) -class FrontLineBounds: - left_position: Point - right_position: Point - - @cached_property - def length(self) -> int: - return int(self.left_position.distance_to_point(self.right_position)) - - @cached_property - def center(self) -> Point: - return (self.left_position + self.right_position) / 2 - - @cached_property - def heading_from_left_to_right(self) -> Heading: - return Heading( - int(self.left_position.heading_between_point(self.right_position)) - ) - - -class FrontLineConflictDescription: - def __init__( - self, - theater: ConflictTheater, - front_line: FrontLine, - position: Point, - heading: Optional[Heading] = None, - size: Optional[int] = None, - ): - self.front_line = front_line - self.theater = theater - self.position = position - self.heading = heading - self.size = size - - @property - def blue_cp(self) -> ControlPoint: - return self.front_line.blue_cp - - @property - def red_cp(self) -> ControlPoint: - return self.front_line.red_cp - - @classmethod - def frontline_position( - cls, frontline: FrontLine, theater: ConflictTheater - ) -> Tuple[Point, Heading]: - attack_heading = frontline.blue_forward_heading - position = cls.find_ground_position( - frontline.position, - FRONTLINE_LENGTH, - attack_heading.right, - theater, - ) - return position, attack_heading.opposite - - @classmethod - def frontline_bounds( - cls, front_line: FrontLine, theater: ConflictTheater - ) -> FrontLineBounds: - """ - Returns a vector for a valid frontline location avoiding exclusion zones. - """ - center_position, heading = cls.frontline_position(front_line, theater) - left_heading = heading.left - right_heading = heading.right - left_position = cls.extend_ground_position( - center_position, int(FRONTLINE_LENGTH / 2), left_heading, theater - ) - right_position = cls.extend_ground_position( - center_position, int(FRONTLINE_LENGTH / 2), right_heading, theater - ) - return FrontLineBounds(left_position, right_position) - - @classmethod - def frontline_cas_conflict( - cls, front_line: FrontLine, theater: ConflictTheater - ) -> FrontLineConflictDescription: - # TODO: Break apart the front-line and air conflict descriptions. - # We're wastefully not caching the front-line bounds here because air conflicts - # can't compute bounds, only a position. - bounds = cls.frontline_bounds(front_line, theater) - conflict = FrontLineConflictDescription( - position=bounds.left_position, - heading=bounds.heading_from_left_to_right, - theater=theater, - front_line=front_line, - size=bounds.length, - ) - return conflict - - @classmethod - def extend_ground_position( - cls, - initial: Point, - max_distance: int, - heading: Heading, - theater: ConflictTheater, - ) -> Point: - """Finds the first intersection with an exclusion zone in one heading from an initial point up to max_distance""" - extended = initial.point_from_heading(heading.degrees, max_distance) - if theater.landmap is None: - # TODO: Why is this possible? - return extended - - p0 = ShapelyPoint(initial.x, initial.y) - p1 = ShapelyPoint(extended.x, extended.y) - line = LineString([p0, p1]) - - intersection = line.intersection(theater.landmap.inclusion_zone_only.boundary) - if intersection.is_empty: - # Max extent does not intersect with the boundary of the inclusion - # zone, so the full front line is usable. This does assume that the - # front line was centered on a valid location. - return extended - - # Otherwise extend the front line only up to the intersection. - return initial.point_from_heading(heading.degrees, p0.distance(intersection)) - - @classmethod - def find_ground_position( - cls, - initial: Point, - max_distance: int, - heading: Heading, - theater: ConflictTheater, - ) -> Point: - """Finds a valid ground position for the front line center. - - Checks for positions along the front line first. If none succeed, the nearest - land position to the initial point is used. - """ - if theater.landmap is None: - return initial - - line = LineString( - [ - dcs_to_shapely_point( - initial.point_from_heading(heading.degrees, max_distance) - ), - dcs_to_shapely_point( - initial.point_from_heading(heading.opposite.degrees, max_distance) - ), - ] - ) - masked_front_line = theater.landmap.inclusion_zone_only.intersection(line) - if masked_front_line.is_empty: - return theater.nearest_land_pos(initial) - nearest_good, _ = nearest_points( - masked_front_line, dcs_to_shapely_point(initial) - ) - return initial.new_in_same_map(nearest_good.x, nearest_good.y) diff --git a/game/missiongenerator/kneeboard.py b/game/missiongenerator/kneeboard.py deleted file mode 100644 index b9de7d645..000000000 --- a/game/missiongenerator/kneeboard.py +++ /dev/null @@ -1,812 +0,0 @@ -"""Generates kneeboard pages relevant to the player's mission. - -The player kneeboard includes the following information: - -* Airfield (departure, arrival, divert) info. -* Flight plan (waypoint numbers, names, altitudes). -* Comm channels. -* AWACS info. -* Tanker info. -* JTAC info. - -Things we should add: - -* Flight plan ToT and fuel ladder (current have neither available). -* Support for planning an arrival/divert airfield separate from departure. -* Mission package infrastructure to include information about the larger - mission, i.e. information about the escort flight for a strike package. -* Target information. Steerpoints, preplanned objectives, ToT, etc. - -For multiplayer missions, a kneeboard will be generated per flight. -https://forums.eagle.ru/showthread.php?t=206360 claims that kneeboard pages can -only be added per airframe, so PvP missions where each side have the same -aircraft will be able to see the enemy's kneeboard for the same airframe. -""" -import datetime -import math -import textwrap -from collections import defaultdict -from dataclasses import dataclass -from pathlib import Path -from typing import Dict, Iterator, List, Optional, TYPE_CHECKING, Tuple - -from PIL import Image, ImageDraw, ImageFont -from dcs.mission import Mission -from tabulate import tabulate - -from game.ato.flighttype import FlightType -from game.ato.flightwaypoint import FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.data.alic import AlicCodes -from game.dcs.aircrafttype import AircraftType -from game.radio.radios import RadioFrequency -from game.runways import RunwayData -from game.theater import TheaterGroundObject, TheaterUnit -from game.theater.bullseye import Bullseye -from game.utils import Distance, UnitSystem, meters, mps, pounds -from game.weather.weather import Weather -from .aircraft.flightdata import FlightData -from .airsupportgenerator import AwacsInfo, TankerInfo -from .briefinggenerator import CommInfo, JtacInfo, MissionInfoGenerator -from ..ato import Package - -if TYPE_CHECKING: - from game import Game - - -class KneeboardPageWriter: - """Creates kneeboard images.""" - - def __init__( - self, page_margin: int = 24, line_spacing: int = 12, dark_theme: bool = False - ) -> None: - if dark_theme: - self.foreground_fill = (215, 200, 200) - self.background_fill = (10, 5, 5) - else: - self.foreground_fill = (15, 15, 15) - self.background_fill = (255, 252, 252) - self.image_size = (768, 1024) - self.image = Image.new("RGB", self.image_size, self.background_fill) - # These font sizes create a relatively full page for current sorties. If - # we start generating more complicated flight plans, or start including - # more information in the comm ladder (the latter of which we should - # probably do), we'll need to split some of this information off into a - # second page. - self.title_font = ImageFont.truetype("arial.ttf", 32) - self.heading_font = ImageFont.truetype("arial.ttf", 24) - self.content_font = ImageFont.truetype("arial.ttf", 16) - self.table_font = ImageFont.truetype("resources/fonts/Inconsolata.otf", 20) - self.draw = ImageDraw.Draw(self.image) - self.page_margin = page_margin - self.x = page_margin - self.y = page_margin - self.line_spacing = line_spacing - - @property - def position(self) -> Tuple[int, int]: - return self.x, self.y - - def text( - self, - text: str, - font: Optional[ImageFont.FreeTypeFont] = None, - fill: Optional[Tuple[int, int, int]] = None, - wrap: bool = False, - ) -> None: - if font is None: - font = self.content_font - if fill is None: - fill = self.foreground_fill - - if wrap: - text = "\n".join( - self.wrap_line_with_font( - line, self.image_size[0] - self.page_margin - self.x, font - ) - for line in text.splitlines() - ) - - self.draw.text(self.position, text, font=font, fill=fill) - left, top, right, bottom = self.draw.textbbox((0, 0), text, font=font) - height = bottom - top - self.y += height + self.line_spacing - - def title(self, title: str) -> None: - self.text(title, font=self.title_font, fill=self.foreground_fill) - - def heading(self, text: str) -> None: - self.text(text, font=self.heading_font, fill=self.foreground_fill) - - def table( - self, - cells: List[List[str]], - headers: Optional[List[str]] = None, - font: Optional[ImageFont.FreeTypeFont] = None, - ) -> None: - if headers is None: - headers = [] - if font is None: - font = self.table_font - table = tabulate(cells, headers=headers, numalign="right") - self.text(table, font, fill=self.foreground_fill) - - def write(self, path: Path) -> None: - self.image.save(path) - - @staticmethod - def wrap_line(inputstr: str, max_length: int) -> str: - if len(inputstr) <= max_length: - return inputstr - tokens = inputstr.split(" ") - output = "" - segments = [] - for token in tokens: - combo = output + " " + token - if len(combo) > max_length: - combo = output + "\n" + token - segments.append(combo) - output = "" - else: - output = combo - return "".join(segments + [output]).strip() - - @staticmethod - def wrap_line_with_font( - inputstr: str, max_width: int, font: ImageFont.FreeTypeFont - ) -> str: - if font.getsize(inputstr)[0] <= max_width: - return inputstr - tokens = inputstr.split(" ") - output = "" - segments = [] - for token in tokens: - combo = output + " " + token - if font.getsize(combo)[0] > max_width: - segments.append(output + "\n") - output = token - else: - output = combo - return "".join(segments + [output]).strip() - - -class KneeboardPage: - """Base class for all kneeboard pages.""" - - def write(self, path: Path) -> None: - """Writes the kneeboard page to the given path.""" - raise NotImplementedError - - -@dataclass(frozen=True) -class NumberedWaypoint: - number: int - waypoint: FlightWaypoint - - -class FlightPlanBuilder: - WAYPOINT_DESC_MAX_LEN = 25 - - def __init__(self, start_time: datetime.datetime, units: UnitSystem) -> None: - self.start_time = start_time - self.rows: List[List[str]] = [] - self.target_points: List[NumberedWaypoint] = [] - self.last_waypoint: Optional[FlightWaypoint] = None - self.units = units - - def add_waypoint(self, waypoint_num: int, waypoint: FlightWaypoint) -> None: - if waypoint.waypoint_type == FlightWaypointType.TARGET_POINT: - self.target_points.append(NumberedWaypoint(waypoint_num, waypoint)) - return - - if self.target_points: - self.coalesce_target_points() - self.target_points = [] - - self.add_waypoint_row(NumberedWaypoint(waypoint_num, waypoint)) - self.last_waypoint = waypoint - - def coalesce_target_points(self) -> None: - if len(self.target_points) <= 4: - for steerpoint in self.target_points: - self.add_waypoint_row(steerpoint) - return - - first_waypoint_num = self.target_points[0].number - last_waypoint_num = self.target_points[-1].number - - self.rows.append( - [ - f"{first_waypoint_num}-{last_waypoint_num}", - "Target points", - "0", - self._waypoint_distance(self.target_points[0].waypoint), - self._ground_speed(self.target_points[0].waypoint), - self._format_time(self.target_points[0].waypoint.tot), - self._format_time(self.target_points[0].waypoint.departure_time), - self._format_min_fuel(self.target_points[0].waypoint.min_fuel), - ] - ) - self.last_waypoint = self.target_points[-1].waypoint - - def add_waypoint_row(self, waypoint: NumberedWaypoint) -> None: - self.rows.append( - [ - str(waypoint.number), - KneeboardPageWriter.wrap_line( - waypoint.waypoint.pretty_name, - FlightPlanBuilder.WAYPOINT_DESC_MAX_LEN, - ), - self._format_alt(waypoint.waypoint.alt), - self._waypoint_distance(waypoint.waypoint), - self._waypoint_bearing(waypoint.waypoint), - self._ground_speed(waypoint.waypoint), - self._format_time(waypoint.waypoint.tot), - self._format_time(waypoint.waypoint.departure_time), - self._format_min_fuel(waypoint.waypoint.min_fuel), - ] - ) - - @staticmethod - def _format_time(time: datetime.datetime | None) -> str: - if time is None: - return "" - return f"{time.strftime('%H:%M:%S')}{'Z' if time.tzinfo is not None else ''}" - - def _format_alt(self, alt: Distance) -> str: - return f"{self.units.distance_short(alt):.0f}" - - def _waypoint_distance(self, waypoint: FlightWaypoint) -> str: - if self.last_waypoint is None: - return "-" - - distance = meters( - self.last_waypoint.position.distance_to_point(waypoint.position) - ) - - return f"{self.units.distance_long(distance):.1f}" - - def _waypoint_bearing(self, waypoint: FlightWaypoint) -> str: - if self.last_waypoint is None: - return "-" - bearing = self.last_waypoint.position.heading_between_point(waypoint.position) - - return f"{(bearing):.0f}" - - def _ground_speed(self, waypoint: FlightWaypoint) -> str: - if self.last_waypoint is None: - return "-" - - if waypoint.tot is None: - return "-" - - if self.last_waypoint.departure_time is not None: - last_time = self.last_waypoint.departure_time - elif self.last_waypoint.tot is not None: - last_time = self.last_waypoint.tot - else: - return "-" - - speed = mps( - self.last_waypoint.position.distance_to_point(waypoint.position) - / (waypoint.tot - last_time).total_seconds() - ) - - return f"{self.units.speed(speed):.0f}" - - def _format_min_fuel(self, min_fuel: Optional[float]) -> str: - if min_fuel is None: - return "" - - mass = pounds(min_fuel) - return f"{math.ceil(self.units.mass(mass) / 100) * 100:.0f}" - - def build(self) -> List[List[str]]: - return self.rows - - -class BriefingPage(KneeboardPage): - """A kneeboard page containing briefing information.""" - - def __init__( - self, - flight: FlightData, - bullseye: Bullseye, - weather: Weather, - start_time: datetime.datetime, - dark_kneeboard: bool, - ) -> None: - self.flight = flight - self.bullseye = bullseye - self.weather = weather - self.start_time = start_time - self.dark_kneeboard = dark_kneeboard - self.flight_plan_font = ImageFont.truetype( - "resources/fonts/Inconsolata.otf", 16 - ) - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - if self.flight.custom_name is not None: - custom_name_title = ' ("{}")'.format(self.flight.custom_name) - else: - custom_name_title = "" - writer.title(f"{self.flight.callsign} Mission Info{custom_name_title}") - - # TODO: Handle carriers. - writer.heading("Airfield Info") - writer.table( - [ - self.airfield_info_row("Departure", self.flight.departure), - self.airfield_info_row("Arrival", self.flight.arrival), - self.airfield_info_row("Divert", self.flight.divert), - ], - headers=["", "Airbase", "ATC", "TCN", "I(C)LS", "RWY"], - ) - - writer.heading("Flight Plan") - - units = self.flight.aircraft_type.kneeboard_units - - flight_plan_builder = FlightPlanBuilder(self.start_time, units) - for num, waypoint in enumerate(self.flight.waypoints): - flight_plan_builder.add_waypoint(num, waypoint) - - uom_row = [ - [ - "", - "", - units.distance_short_uom, - units.distance_long_uom, - "T", - units.speed_uom, - "", - "", - units.mass_uom, - ] - ] - - writer.table( - flight_plan_builder.build() + uom_row, - headers=[ - "#", - "Action", - "Alt", - "Dist", - "Brg", - "GSPD", - "Time", - "Departure", - "Min fuel", - ], - font=self.flight_plan_font, - ) - - writer.text(f"Bullseye: {self.bullseye.position.latlng().format_dms()}") - - qnh_in_hg = f"{self.weather.atmospheric.qnh.inches_hg:.2f}" - qnh_mm_hg = f"{self.weather.atmospheric.qnh.mm_hg:.1f}" - qnh_hpa = f"{self.weather.atmospheric.qnh.hecto_pascals:.1f}" - writer.text( - f"Temperature: {round(self.weather.atmospheric.temperature_celsius)} °C at sea level" - ) - writer.text(f"QNH: {qnh_in_hg} inHg / {qnh_mm_hg} mmHg / {qnh_hpa} hPa") - writer.text( - f"Turbulence: {round(self.weather.atmospheric.turbulence_per_10cm)} per 10cm at ground level." - ) - - fl = self.flight - - if fl.bingo_fuel and fl.joker_fuel: - writer.table( - [ - [ - f"{units.mass(pounds(fl.bingo_fuel)):.0f} {units.mass_uom}", - f"{units.mass(pounds(fl.joker_fuel)):.0f} {units.mass_uom}", - ] - ], - ["Bingo", "Joker"], - ) - - if any(self.flight.laser_codes): - codes: list[list[str]] = [] - for idx, code in enumerate(self.flight.laser_codes, start=1): - codes.append([str(idx), "" if code is None else str(code)]) - writer.table(codes, ["#", "Laser Code"]) - - writer.write(path) - - def airfield_info_row( - self, row_title: str, runway: Optional[RunwayData] - ) -> List[str]: - """Creates a table row for a given airfield. - - Args: - row_title: Purpose of the airfield. e.g. "Departure", "Arrival" or - "Divert". - runway: The runway described by this row. - - Returns: - A list of strings to be used as a row of the airfield table. - """ - if runway is None: - return [row_title, "", "", "", "", ""] - - atc = "" - if runway.atc is not None: - atc = self.format_frequency(runway.atc) - if runway.tacan is None: - tacan = "" - else: - tacan = str(runway.tacan) - if runway.ils is not None: - ils = str(runway.ils) - elif runway.icls is not None: - ils = str(runway.icls) - else: - ils = "" - return [ - row_title, - "\n".join(textwrap.wrap(runway.airfield_name, width=24)), - atc, - tacan, - ils, - runway.runway_name, - ] - - def format_frequency(self, frequency: RadioFrequency) -> str: - channel = self.flight.channel_for(frequency) - if channel is None: - return str(frequency) - - channel_name = self.flight.aircraft_type.channel_name( - channel.radio_id, channel.channel - ) - return f"{channel_name}\n{frequency}" - - -class SupportPage(KneeboardPage): - """A kneeboard page containing information about support units.""" - - JTAC_REGION_MAX_LEN = 25 - - def __init__( - self, - flight: FlightData, - comms: List[CommInfo], - awacs: List[AwacsInfo], - tankers: List[TankerInfo], - jtacs: List[JtacInfo], - start_time: datetime.datetime, - dark_kneeboard: bool, - ) -> None: - self.flight = flight - self.comms = list(comms) - self.awacs = awacs - self.tankers = tankers - self.jtacs = jtacs - self.start_time = start_time - self.dark_kneeboard = dark_kneeboard - self.comms.append(CommInfo("Flight", self.flight.intra_flight_channel)) - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - if self.flight.custom_name is not None: - custom_name_title = ' ("{}")'.format(self.flight.custom_name) - else: - custom_name_title = "" - writer.title(f"{self.flight.callsign} Support Info{custom_name_title}") - - # AEW&C - writer.heading("AEW&C") - aewc_ladder = [] - - for single_aewc in self.awacs: - if single_aewc.depature_location is None: - dep = "-" - arr = "-" - else: - dep = self._format_time(single_aewc.start_time) - arr = self._format_time(single_aewc.end_time) - - aewc_ladder.append( - [ - str(single_aewc.callsign), - self.format_frequency(single_aewc.freq), - str(single_aewc.depature_location), - str(dep), - str(arr), - ] - ) - - writer.table( - aewc_ladder, - headers=["Callsign", "FREQ", "Depature", "ETD", "ETA"], - ) - - # Package Section - writer.heading("Comm ladder") - comm_ladder = [] - for comm in self.comms: - comm_ladder.append( - [comm.name, "", "", "", self.format_frequency(comm.freq)] - ) - - for tanker in self.tankers: - comm_ladder.append( - [ - tanker.callsign, - "Tanker", - tanker.variant, - str(tanker.tacan), - self.format_frequency(tanker.freq), - ] - ) - - writer.table(comm_ladder, headers=["Callsign", "Task", "Type", "TACAN", "FREQ"]) - - writer.heading("JTAC") - jtacs = [] - for jtac in self.jtacs: - jtacs.append( - [ - jtac.callsign, - KneeboardPageWriter.wrap_line( - jtac.region, - self.JTAC_REGION_MAX_LEN, - ), - jtac.code, - self.format_frequency(jtac.freq), - ] - ) - writer.table(jtacs, headers=["Callsign", "Region", "Laser Code", "FREQ"]) - - writer.write(path) - - def format_frequency(self, frequency: RadioFrequency) -> str: - channel = self.flight.channel_for(frequency) - if channel is None: - return str(frequency) - - channel_name = self.flight.aircraft_type.channel_name( - channel.radio_id, channel.channel - ) - return f"{channel_name}\n{frequency}" - - @staticmethod - def _format_time(time: datetime.datetime | None) -> str: - if time is None: - return "" - return f"{time.strftime('%H:%M:%S')}{'Z' if time.tzinfo is not None else ''}" - - -class SeadTaskPage(KneeboardPage): - """A kneeboard page containing SEAD/DEAD target information.""" - - def __init__(self, flight: FlightData, dark_kneeboard: bool) -> None: - self.flight = flight - self.dark_kneeboard = dark_kneeboard - - @property - def target_units(self) -> Iterator[TheaterUnit]: - if isinstance(self.flight.package.target, TheaterGroundObject): - yield from self.flight.package.target.strike_targets - - @staticmethod - def alic_for(unit: TheaterUnit) -> str: - try: - return str(AlicCodes.code_for(unit)) - except KeyError: - return "" - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - if self.flight.custom_name is not None: - custom_name_title = ' ("{}")'.format(self.flight.custom_name) - else: - custom_name_title = "" - task = "DEAD" if self.flight.flight_type == FlightType.DEAD else "SEAD" - writer.title(f"{self.flight.callsign} {task} Target Info{custom_name_title}") - - writer.table( - [self.target_info_row(t) for t in self.target_units], - headers=["Description", "ALIC", "Location"], - ) - - writer.write(path) - - def target_info_row(self, unit: TheaterUnit) -> List[str]: - ll = unit.position.latlng() - unit_type = unit.type - name = unit.name if unit_type is None else unit_type.name - return [ - name, - self.alic_for(unit), - ll.format_dms(include_decimal_seconds=True), - ] - - -class StrikeTaskPage(KneeboardPage): - """A kneeboard page containing strike target information.""" - - def __init__(self, flight: FlightData, dark_kneeboard: bool) -> None: - self.flight = flight - self.dark_kneeboard = dark_kneeboard - - @property - def targets(self) -> Iterator[NumberedWaypoint]: - for idx, waypoint in enumerate(self.flight.waypoints): - if waypoint.waypoint_type == FlightWaypointType.TARGET_POINT: - yield NumberedWaypoint(idx, waypoint) - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - if self.flight.custom_name is not None: - custom_name_title = ' ("{}")'.format(self.flight.custom_name) - else: - custom_name_title = "" - writer.title(f"{self.flight.callsign} Strike Task Info{custom_name_title}") - - writer.table( - [self.target_info_row(t) for t in self.targets], - headers=["Steerpoint", "Description", "Location"], - ) - - writer.write(path) - - @staticmethod - def target_info_row(target: NumberedWaypoint) -> list[str]: - return [ - str(target.number), - target.waypoint.pretty_name, - target.waypoint.position.latlng().format_dms(include_decimal_seconds=True), - ] - - -class NotesPage(KneeboardPage): - """A kneeboard page containing the campaign owner's notes.""" - - def __init__( - self, - notes: str, - dark_kneeboard: bool, - ) -> None: - self.notes = notes - self.dark_kneeboard = dark_kneeboard - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - writer.title(f"Notes") - writer.text(self.notes, wrap=True) - writer.write(path) - - -class PackagePage(KneeboardPage): - """A kneeboard page showing information about the flight's package.""" - - def __init__( - self, package: Package, flights: list[FlightData], dark_kneeboard: bool - ) -> None: - self.package = package - self.flights = flights - self.dark_kneeboard = dark_kneeboard - - def write(self, path: Path) -> None: - writer = KneeboardPageWriter(dark_theme=self.dark_kneeboard) - writer.title( - f"Package {self.package.package_description} {self.package.target.name}" - ) - - table = [] - for flight in self.flights: - for idx, laser_code in enumerate(flight.laser_codes, 1): - # Blank the flight-wide properties to make the table easier to scan. - if idx > 1: - task = "" - radio = "" - else: - task = str(flight.flight_type) - radio = str(flight.intra_flight_channel) - - table.append( - [ - f"{flight.callsign}-{idx}", - task, - radio, - "" if laser_code is None else str(laser_code), - ] - ) - writer.table(table, ["Aircraft", "Task", "Radio", "Laser code"]) - - writer.write(path) - - -class KneeboardGenerator(MissionInfoGenerator): - """Creates kneeboard pages for each client flight in the mission.""" - - def __init__(self, mission: Mission, game: "Game") -> None: - super().__init__(mission, game) - self.dark_kneeboard = self.game.settings.generate_dark_kneeboard and ( - self.mission.start_time.hour > 19 or self.mission.start_time.hour < 7 - ) - - def generate(self) -> None: - """Generates a kneeboard per client flight.""" - temp_dir = Path("kneeboards") - temp_dir.mkdir(exist_ok=True) - for aircraft, pages in self.pages_by_airframe().items(): - aircraft_dir = temp_dir / aircraft.dcs_unit_type.id - aircraft_dir.mkdir(exist_ok=True) - for idx, page in enumerate(pages): - page_path = aircraft_dir / f"page{idx:02}.png" - page.write(page_path) - self.mission.add_aircraft_kneeboard(aircraft.dcs_unit_type, page_path) - - def pages_by_airframe(self) -> Dict[AircraftType, List[KneeboardPage]]: - """Returns a list of kneeboard pages per airframe in the mission. - - Only client flights will be included, but because DCS does not support - group-specific kneeboard pages, flights (possibly from opposing sides) - will be able to see the kneeboards of all aircraft of the same type. - - Returns: - A dict mapping aircraft types to the list of kneeboard pages for - that aircraft. - """ - all_flights: Dict[AircraftType, List[KneeboardPage]] = defaultdict(list) - for flights in self.briefing_data: - for flight in flights: - if not flight.client_units: - continue - all_flights[flight.aircraft_type].extend( - self.generate_flight_kneeboard(flight, flights) - ) - return all_flights - - def generate_task_page(self, flight: FlightData) -> Optional[KneeboardPage]: - if flight.flight_type in (FlightType.DEAD, FlightType.SEAD): - return SeadTaskPage(flight, self.dark_kneeboard) - elif flight.flight_type is FlightType.STRIKE: - return StrikeTaskPage(flight, self.dark_kneeboard) - return None - - def generate_flight_kneeboard( - self, flight: FlightData, flights: list[FlightData] - ) -> List[KneeboardPage]: - """Returns a list of kneeboard pages for the given flight.""" - - if flight.aircraft_type.utc_kneeboard: - zoned_time = self.game.conditions.start_time.replace( - tzinfo=self.game.theater.timezone - ).astimezone(datetime.timezone.utc) - else: - zoned_time = self.game.conditions.start_time - - pages: List[KneeboardPage] = [ - BriefingPage( - flight, - self.game.coalition_for(flight.friendly).bullseye, - self.game.conditions.weather, - zoned_time, - self.dark_kneeboard, - ), - SupportPage( - flight, - self.comms, - self.awacs, - self.tankers, - self.jtacs, - zoned_time, - self.dark_kneeboard, - ), - PackagePage(flight.package, flights, self.dark_kneeboard), - ] - - # Only create the notes page if there are notes to show. - if notes := self.game.notes: - pages.append(NotesPage(notes, self.dark_kneeboard)) - - if (target_page := self.generate_task_page(flight)) is not None: - pages.append(target_page) - - return pages diff --git a/game/missiongenerator/logisticsgenerator.py b/game/missiongenerator/logisticsgenerator.py deleted file mode 100644 index 089a6bda8..000000000 --- a/game/missiongenerator/logisticsgenerator.py +++ /dev/null @@ -1,105 +0,0 @@ -from typing import Any, Optional - -from dcs import Mission -from dcs.statics import Fortification -from dcs.unitgroup import FlyingGroup - -from game.ato import Flight -from game.ato.flightplans.airassault import AirAssaultFlightPlan -from game.ato.flightwaypointtype import FlightWaypointType -from game.missiongenerator.missiondata import CargoInfo, LogisticsInfo -from game.plugins import LuaPluginManager -from game.transfers import TransferOrder - -ZONE_RADIUS = 300 -CRATE_ZONE_RADIUS = 50 - - -class LogisticsGenerator: - def __init__( - self, - flight: Flight, - group: FlyingGroup[Any], - mission: Mission, - lua_plugin_manager: LuaPluginManager, - transfer: Optional[TransferOrder] = None, - ) -> None: - self.flight = flight - self.group = group - self.transfer = transfer - self.mission = mission - self.lua_plugin_manager = lua_plugin_manager - - def generate_logistics(self) -> LogisticsInfo: - # Add Logisitcs info for the flight - logistics_info = LogisticsInfo( - pilot_names=[u.name for u in self.group.units], - transport=self.flight.squadron.aircraft, - blue=self.flight.blue, - preload=self.flight.state.in_flight, - ) - - if isinstance(self.flight.flight_plan, AirAssaultFlightPlan): - # Preload fixed wing as they do not have a pickup zone - logistics_info.preload = logistics_info.preload or not self.flight.is_helo - # Create the Waypoint Zone used by CTLD - target_zone = f"{self.group.name}TARGET_ZONE" - self.mission.triggers.add_triggerzone( - self.flight.flight_plan.layout.target.position, - self.flight.flight_plan.ctld_target_zone_radius.meters, - False, - target_zone, - ) - logistics_info.target_zone = target_zone - - pickup_point = None - for waypoint in self.flight.points: - if ( - waypoint.waypoint_type - not in [ - FlightWaypointType.PICKUP_ZONE, - FlightWaypointType.DROPOFF_ZONE, - ] - or waypoint.only_for_player - and not self.flight.client_count - ): - continue - # Create Pickup and DropOff zone - zone_name = f"{self.group.name}{waypoint.waypoint_type.name}" - self.mission.triggers.add_triggerzone( - waypoint.position, ZONE_RADIUS, False, zone_name - ) - if waypoint.waypoint_type == FlightWaypointType.PICKUP_ZONE: - pickup_point = waypoint.position - logistics_info.pickup_zone = zone_name - else: - logistics_info.drop_off_zone = zone_name - - if self.transfer and self.flight.client_count > 0 and pickup_point is not None: - # Add spawnable crates for client airlifts - crate_location = pickup_point.random_point_within( - ZONE_RADIUS - CRATE_ZONE_RADIUS, CRATE_ZONE_RADIUS - ) - crate_zone = f"{self.group.name}crate_spawn" - self.mission.triggers.add_triggerzone( - crate_location, CRATE_ZONE_RADIUS, False, crate_zone - ) - logistics_info.cargo = [ - CargoInfo(cargo_unit_type.dcs_id, crate_zone, amount) - for cargo_unit_type, amount in self.transfer.units.items() - ] - - if pickup_point is not None and self.lua_plugin_manager.is_option_enabled( - "ctld", "logisticunit" - ): - # Spawn logisticsunit at pickup zones - country = self.mission.country(self.flight.country) - logistic_unit = self.mission.static_group( - country, - f"{self.group.name}logistic", - Fortification.FARP_Ammo_Dump_Coating, - pickup_point, - ) - logistics_info.logistic_unit = logistic_unit.units[0].name - - return logistics_info diff --git a/game/missiongenerator/luagenerator.py b/game/missiongenerator/luagenerator.py deleted file mode 100644 index 29a448e3f..000000000 --- a/game/missiongenerator/luagenerator.py +++ /dev/null @@ -1,405 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -import os -from abc import ABC, abstractmethod -from pathlib import Path -from typing import Optional, TYPE_CHECKING - -from dcs import Mission -from dcs.action import DoScript, DoScriptFile -from dcs.translation import String -from dcs.triggers import TriggerStart - -from game.ato import FlightType -from game.dcs.aircrafttype import AircraftType -from game.theater import TheaterGroundObject -from game.theater.iadsnetwork.iadsrole import IadsRole -from game.utils import escape_string_for_lua -from .missiondata import MissionData - -if TYPE_CHECKING: - from game import Game - - -class LuaGenerator: - def __init__( - self, - game: Game, - mission: Mission, - mission_data: MissionData, - ) -> None: - self.game = game - self.mission = mission - self.mission_data = mission_data - self.plugin_scripts: list[str] = [] - - def generate(self) -> None: - self.generate_plugin_data() - self.inject_plugins() - - def generate_plugin_data(self) -> None: - lua_data = LuaData("dcsLiberation") - - install_path = lua_data.add_item("installPath") - install_path.set_value(os.path.abspath(".")) - - lua_data.add_item("Airbases") - carriers_object = lua_data.add_item("Carriers") - - for carrier in self.mission_data.carriers: - carrier_item = carriers_object.add_item() - carrier_item.add_key_value("dcsGroupName", carrier.group_name) - carrier_item.add_key_value("unit_name", carrier.unit_name) - carrier_item.add_key_value("callsign", carrier.callsign) - carrier_item.add_key_value("radio", str(carrier.freq.mhz)) - carrier_item.add_key_value( - "tacan", str(carrier.tacan.number) + carrier.tacan.band.name - ) - - tankers_object = lua_data.add_item("Tankers") - for tanker in self.mission_data.tankers: - tanker_item = tankers_object.add_item() - tanker_item.add_key_value("dcsGroupName", tanker.group_name) - tanker_item.add_key_value("callsign", tanker.callsign) - tanker_item.add_key_value("variant", tanker.variant) - tanker_item.add_key_value("radio", str(tanker.freq.mhz)) - tanker_item.add_key_value( - "tacan", str(tanker.tacan.number) + tanker.tacan.band.name - ) - - awacs_object = lua_data.add_item("AWACs") - for awacs in self.mission_data.awacs: - awacs_item = awacs_object.add_item() - awacs_item.add_key_value("dcsGroupName", awacs.group_name) - awacs_item.add_key_value("callsign", awacs.callsign) - awacs_item.add_key_value("radio", str(awacs.freq.mhz)) - - jtacs_object = lua_data.add_item("JTACs") - for jtac in self.mission_data.jtacs: - jtac_item = jtacs_object.add_item() - jtac_item.add_key_value("dcsGroupName", jtac.group_name) - jtac_item.add_key_value("callsign", jtac.callsign) - jtac_item.add_key_value("zone", jtac.region) - jtac_item.add_key_value("dcsUnit", jtac.unit_name) - jtac_item.add_key_value("laserCode", jtac.code) - jtac_item.add_key_value("radio", str(jtac.freq.mhz)) - jtac_item.add_key_value("modulation", jtac.freq.modulation.name) - - logistics_object = lua_data.add_item("Logistics") - logistics_flights = logistics_object.add_item("flights") - crates_object = logistics_object.add_item("crates") - spawnable_crates: dict[str, str] = {} - transports: list[AircraftType] = [] - for logistic_info in self.mission_data.logistics: - if logistic_info.transport not in transports: - transports.append(logistic_info.transport) - coalition_color = "blue" if logistic_info.blue else "red" - logistics_item = logistics_flights.add_item() - logistics_item.add_data_array("pilot_names", logistic_info.pilot_names) - logistics_item.add_key_value("pickup_zone", logistic_info.pickup_zone) - logistics_item.add_key_value("drop_off_zone", logistic_info.drop_off_zone) - logistics_item.add_key_value("target_zone", logistic_info.target_zone) - logistics_item.add_key_value("side", str(2 if logistic_info.blue else 1)) - logistics_item.add_key_value("logistic_unit", logistic_info.logistic_unit) - logistics_item.add_key_value( - "aircraft_type", logistic_info.transport.dcs_id - ) - logistics_item.add_key_value( - "preload", "true" if logistic_info.preload else "false" - ) - for cargo in logistic_info.cargo: - if cargo.unit_type not in spawnable_crates: - spawnable_crates[cargo.unit_type] = str(200 + len(spawnable_crates)) - crate_weight = spawnable_crates[cargo.unit_type] - for i in range(cargo.amount): - cargo_item = crates_object.add_item() - cargo_item.add_key_value("weight", crate_weight) - cargo_item.add_key_value("coalition", coalition_color) - cargo_item.add_key_value("zone", cargo.spawn_zone) - transport_object = logistics_object.add_item("transports") - for transport in transports: - transport_item = transport_object.add_item() - transport_item.add_key_value("aircraft_type", transport.dcs_id) - transport_item.add_key_value("cabin_size", str(transport.cabin_size)) - transport_item.add_key_value( - "troops", "true" if transport.cabin_size > 0 else "false" - ) - transport_item.add_key_value( - "crates", "true" if transport.can_carry_crates else "false" - ) - spawnable_crates_object = logistics_object.add_item("spawnable_crates") - for unit, weight in spawnable_crates.items(): - crate_item = spawnable_crates_object.add_item() - crate_item.add_key_value("unit", unit) - crate_item.add_key_value("weight", weight) - - target_points = lua_data.add_item("TargetPoints") - all_packages = itertools.chain( - self.game.blue.ato.packages, self.game.red.ato.packages - ) - for package in all_packages: - for flight in package.flights: - if flight.blue and flight.flight_type in [ - FlightType.ANTISHIP, - FlightType.DEAD, - FlightType.SEAD, - FlightType.STRIKE, - ]: - flight_type = str(flight.flight_type) - flight_target = flight.package.target - if flight_target: - flight_target_name = None - flight_target_type = None - if isinstance(flight_target, TheaterGroundObject): - flight_target_name = flight_target.obj_name - flight_target_type = ( - flight_type + f" TGT ({flight_target.category})" - ) - elif hasattr(flight_target, "name"): - flight_target_name = flight_target.name - flight_target_type = flight_type + " TGT (Airbase)" - target_item = target_points.add_item() - if flight_target_name: - target_item.add_key_value("name", flight_target_name) - if flight_target_type: - target_item.add_key_value("type", flight_target_type) - target_item.add_key_value( - "positionX", str(flight_target.position.x) - ) - target_item.add_key_value( - "positionY", str(flight_target.position.y) - ) - - for cp in self.game.theater.controlpoints: - coalition_object = ( - lua_data.get_or_create_item("BlueAA") - if cp.captured - else lua_data.get_or_create_item("RedAA") - ) - for ground_object in cp.ground_objects: - for g in ground_object.groups: - threat_range = g.max_threat_range() - - if not threat_range: - continue - - aa_item = coalition_object.add_item() - aa_item.add_key_value("name", ground_object.name) - aa_item.add_key_value("range", str(threat_range.meters)) - aa_item.add_key_value("positionX", str(ground_object.position.x)) - aa_item.add_key_value("positionY", str(ground_object.position.y)) - - # Generate IADS Lua Item - iads_object = lua_data.add_item("IADS") - # These should always be created even if they are empty. - iads_object.get_or_create_item("BLUE") - iads_object.get_or_create_item("RED") - # Should probably do the same with all the roles... but the script is already - # tolerant of those being empty. - for node in self.game.theater.iads_network.skynet_nodes(self.game): - coalition = iads_object.get_or_create_item("BLUE" if node.player else "RED") - iads_type = coalition.get_or_create_item(node.iads_role.value) - iads_element = iads_type.add_item() - iads_element.add_key_value("dcsGroupName", node.dcs_name) - if node.iads_role in [IadsRole.SAM, IadsRole.SAM_AS_EWR]: - # add additional SkynetProperties to SAM Sites - for property, value in node.properties.items(): - iads_element.add_key_value(property, value) - for role, connections in node.connections.items(): - iads_element.add_data_array(role, connections) - - trigger = TriggerStart(comment="Set DCS Liberation data") - trigger.add_action(DoScript(String(lua_data.create_operations_lua()))) - self.mission.triggerrules.triggers.append(trigger) - - def inject_lua_trigger(self, contents: str, comment: str) -> None: - """Creates the trigger for running the text script at mission start.""" - trigger = TriggerStart(comment=comment) - trigger.add_action(DoScript(String(contents))) - self.mission.triggerrules.triggers.append(trigger) - - def bypass_plugin_script(self, mnemonic: str) -> None: - """Records a script has having been intentionally ignored. - - It's not clear why this is needed. It looks like this might be a holdover from - when mission generation was driven by a singleton and we needed to avoid - double-loading plugins if the generator ran twice (take off, cancel, take off)? - - For now, this prevents duplicates from being handled twice. - """ - self.plugin_scripts.append(mnemonic) - - def inject_plugin_script( - self, plugin_mnemonic: str, script: str, script_mnemonic: str - ) -> None: - """ "Creates a trigger for running the script file at mission start.""" - if script_mnemonic in self.plugin_scripts: - logging.debug(f"Skipping already loaded {script} for {plugin_mnemonic}") - return - - self.plugin_scripts.append(script_mnemonic) - - plugin_path = Path("./resources/plugins", plugin_mnemonic) - - script_path = Path(plugin_path, script) - if not script_path.exists(): - logging.error(f"Cannot find {script_path} for plugin {plugin_mnemonic}") - return - - trigger = TriggerStart(comment=f"Load {script_mnemonic}") - filename = script_path.resolve() - fileref = self.mission.map_resource.add_resource_file(filename) - trigger.add_action(DoScriptFile(fileref)) - self.mission.triggerrules.triggers.append(trigger) - - def inject_plugins(self) -> None: - for plugin in self.game.lua_plugin_manager.iter_plugins(): - if plugin.enabled: - plugin.inject_scripts(self) - plugin.inject_configuration(self) - - -class LuaValue: - key: Optional[str] - value: str | list[str] - - def __init__(self, key: Optional[str], value: str | list[str]): - self.key = key - self.value = value - - def serialize(self) -> str: - serialized_value = self.key + " = " if self.key else "" - if isinstance(self.value, str): - serialized_value += f'"{escape_string_for_lua(self.value)}"' - else: - escaped_values = [f'"{escape_string_for_lua(v)}"' for v in self.value] - serialized_value += "{" + ", ".join(escaped_values) + "}" - return serialized_value - - -class LuaItem(ABC): - value: LuaValue | list[LuaValue] - name: Optional[str] - - def __init__(self, name: Optional[str]): - self.value = [] - self.name = name - - def set_value(self, value: str) -> None: - self.value = LuaValue(None, value) - - def set_data_array(self, values: list[str]) -> None: - self.value = LuaValue(None, values) - - def add_data_array(self, key: str, values: list[str]) -> None: - self._add_value(LuaValue(key, values)) - - def add_key_value(self, key: str, value: str) -> None: - self._add_value(LuaValue(key, value)) - - def _add_value(self, value: LuaValue) -> None: - if isinstance(self.value, list): - self.value.append(value) - else: - self.value = value - - @abstractmethod - def add_item(self, item_name: Optional[str] = None) -> LuaItem: - """adds a new item to the LuaArray without checking the existence""" - raise NotImplementedError - - @abstractmethod - def get_item(self, item_name: str) -> Optional[LuaItem]: - """gets item from LuaArray. Returns None if it does not exist""" - raise NotImplementedError - - @abstractmethod - def get_or_create_item(self, item_name: Optional[str] = None) -> LuaItem: - """gets item from the LuaArray or creates one if it does not exist already""" - raise NotImplementedError - - @abstractmethod - def serialize(self) -> str: - if isinstance(self.value, LuaValue): - return self.value.serialize() - else: - serialized_data = [d.serialize() for d in self.value] - return "{" + ", ".join(serialized_data) + "}" - - -class LuaData(LuaItem): - objects: list[LuaData] - base_name: Optional[str] - - def __init__(self, name: Optional[str], is_base_name: bool = True): - self.objects = [] - self.base_name = name if is_base_name else None - super().__init__(name) - - def add_item(self, item_name: Optional[str] = None) -> LuaItem: - item = LuaData(item_name, False) - self.objects.append(item) - return item - - def get_item(self, item_name: str) -> Optional[LuaItem]: - for lua_object in self.objects: - if lua_object.name == item_name: - return lua_object - return None - - def get_or_create_item(self, item_name: Optional[str] = None) -> LuaItem: - if item_name: - item = self.get_item(item_name) - if item: - return item - return self.add_item(item_name) - - def serialize(self, level: int = 0) -> str: - """serialize the LuaData to a string""" - serialized_data: list[str] = [] - serialized_name = "" - linebreak = "\n" - tab = "\t" - tab_end = "" - for _ in range(level): - tab += "\t" - tab_end += "\t" - if self.base_name: - # Only used for initialization of the object in lua - serialized_name += self.base_name + " = " - if self.objects: - # nested objects - serialized_objects = [o.serialize(level + 1) for o in self.objects] - if self.name: - if self.name is not self.base_name: - serialized_name += self.name + " = " - serialized_data.append( - serialized_name - + "{" - + linebreak - + tab - + ("," + linebreak + tab).join(serialized_objects) - + linebreak - + tab_end - + "}" - ) - else: - # key with value - if self.name: - serialized_data.append(self.name + " = " + super().serialize()) - # only value - else: - serialized_data.append(super().serialize()) - - return "\n".join(serialized_data) - - def create_operations_lua(self) -> str: - """crates the liberation lua script for the dcs mission""" - lua_prefix = """ --- setting configuration table -env.info("DCSLiberation|: setting configuration table") -""" - - return lua_prefix + self.serialize() diff --git a/game/missiongenerator/missiondata.py b/game/missiongenerator/missiondata.py deleted file mode 100644 index 1f6b56096..000000000 --- a/game/missiongenerator/missiondata.py +++ /dev/null @@ -1,96 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from datetime import datetime -from typing import Optional, TYPE_CHECKING - -from game.dcs.aircrafttype import AircraftType -from game.missiongenerator.aircraft.flightdata import FlightData -from game.runways import RunwayData - -if TYPE_CHECKING: - from game.radio.radios import RadioFrequency - from game.radio.tacan import TacanChannel - - -@dataclass -class GroupInfo: - group_name: str - callsign: str - freq: RadioFrequency - blue: bool - - -@dataclass -class UnitInfo(GroupInfo): - unit_name: str - - -@dataclass -class AwacsInfo(GroupInfo): - """AWACS information for the kneeboard.""" - - depature_location: Optional[str] - start_time: datetime | None - end_time: datetime | None - - -@dataclass -class TankerInfo(GroupInfo): - """Tanker information for the kneeboard.""" - - variant: str - tacan: TacanChannel - start_time: datetime | None - end_time: datetime | None - - -@dataclass -class CarrierInfo(UnitInfo): - """Carrier information.""" - - tacan: TacanChannel - - -@dataclass -class JtacInfo(UnitInfo): - """JTAC information.""" - - region: str - code: str - - -@dataclass -class CargoInfo: - """Cargo information.""" - - unit_type: str = field(default_factory=str) - spawn_zone: str = field(default_factory=str) - amount: int = field(default=1) - - -@dataclass -class LogisticsInfo: - """Logistics information.""" - - pilot_names: list[str] - transport: AircraftType - blue: bool - - logistic_unit: str = field(default_factory=str) - pickup_zone: str = field(default_factory=str) - drop_off_zone: str = field(default_factory=str) - target_zone: str = field(default_factory=str) - cargo: list[CargoInfo] = field(default_factory=list) - preload: bool = field(default=False) - - -@dataclass -class MissionData: - awacs: list[AwacsInfo] = field(default_factory=list) - runways: list[RunwayData] = field(default_factory=list) - carriers: list[CarrierInfo] = field(default_factory=list) - briefing_data: list[list[FlightData]] = field(default_factory=list) - tankers: list[TankerInfo] = field(default_factory=list) - jtacs: list[JtacInfo] = field(default_factory=list) - logistics: list[LogisticsInfo] = field(default_factory=list) diff --git a/game/missiongenerator/missiongenerator.py b/game/missiongenerator/missiongenerator.py deleted file mode 100644 index 75d006696..000000000 --- a/game/missiongenerator/missiongenerator.py +++ /dev/null @@ -1,363 +0,0 @@ -from __future__ import annotations - -import logging -from datetime import datetime -from pathlib import Path -from typing import TYPE_CHECKING, cast - -import dcs.lua -from dcs import Mission, Point -from dcs.coalition import Coalition -from dcs.countries import country_dict - -from game.atcdata import AtcData -from game.dcs.beacons import Beacons -from game.dcs.helpers import unit_type_from_name -from game.ground_forces.ai_ground_planner import GroundPlanner -from game.missiongenerator.aircraft.aircraftgenerator import ( - AircraftGenerator, -) -from game.naming import namegen -from game.radio.radios import RadioFrequency, RadioRegistry -from game.radio.tacan import TacanRegistry -from game.theater import Airfield -from game.theater.bullseye import Bullseye -from game.unitmap import UnitMap -from .airconflictdescription import AirConflictDescription -from .airsupportgenerator import AirSupportGenerator -from .briefinggenerator import BriefingGenerator, MissionInfoGenerator -from .cargoshipgenerator import CargoShipGenerator -from .convoygenerator import ConvoyGenerator -from .drawingsgenerator import DrawingsGenerator -from .environmentgenerator import EnvironmentGenerator -from .flotgenerator import FlotGenerator -from .forcedoptionsgenerator import ForcedOptionsGenerator -from .frontlineconflictdescription import FrontLineConflictDescription -from .kneeboard import KneeboardGenerator -from .luagenerator import LuaGenerator -from .missiondata import MissionData -from .tgogenerator import TgoGenerator -from .triggergenerator import TriggerGenerator -from .visualsgenerator import VisualsGenerator - -if TYPE_CHECKING: - from game import Game - from game.theater import ControlPoint - from game.ground_forces.ai_ground_planner import CombatGroup - -COMBINED_ARMS_SLOTS = 1 - - -def country_id_from_name(name: str) -> int: - for k, v in country_dict.items(): - if v.name == name: - return k - return -1 - - -class MissionGenerator: - def __init__(self, game: Game, time: datetime) -> None: - self.game = game - self.time = time - self.mission = Mission(game.theater.terrain) - self.unit_map = UnitMap() - - self.mission_data = MissionData() - - self.radio_registry = RadioRegistry() - self.tacan_registry = TacanRegistry() - - self.generation_started = False - - with open("resources/default_options.lua", "r", encoding="utf-8") as f: - self.mission.options.load_from_dict(dcs.lua.loads(f.read())["options"]) - - def generate_miz(self, output: Path) -> UnitMap: - if self.generation_started: - raise RuntimeError( - "Mission has already begun generating. To reset, create a new " - "MissionSimulation." - ) - self.generation_started = True - - self.setup_mission_coalitions() - self.add_airfields_to_unit_map() - self.initialize_registries() - - EnvironmentGenerator(self.mission, self.game.conditions, self.time).generate() - - tgo_generator = TgoGenerator( - self.mission, - self.game, - self.radio_registry, - self.tacan_registry, - self.unit_map, - self.mission_data, - ) - tgo_generator.generate() - - ConvoyGenerator(self.mission, self.game, self.unit_map).generate() - CargoShipGenerator(self.mission, self.game, self.unit_map).generate() - - self.generate_destroyed_units() - - # Generate ground conflicts first so the JTACs get the first laser code (1688) - # rather than the first player flight with a TGP. - self.generate_ground_conflicts() - self.generate_air_units(tgo_generator) - - TriggerGenerator(self.mission, self.game).generate() - ForcedOptionsGenerator(self.mission, self.game).generate() - VisualsGenerator(self.mission, self.game).generate() - LuaGenerator(self.game, self.mission, self.mission_data).generate() - DrawingsGenerator(self.mission, self.game).generate() - - self.setup_combined_arms() - - self.notify_info_generators() - - # TODO: Shouldn't this be first? - namegen.reset_numbers() - self.mission.save(output) - - return self.unit_map - - def setup_mission_coalitions(self) -> None: - self.mission.coalition["blue"] = Coalition( - "blue", bullseye=self.game.blue.bullseye.to_pydcs() - ) - self.mission.coalition["red"] = Coalition( - "red", bullseye=self.game.red.bullseye.to_pydcs() - ) - self.mission.coalition["neutrals"] = Coalition( - "neutrals", bullseye=Bullseye(Point(0, 0, self.mission.terrain)).to_pydcs() - ) - - p_country = self.game.blue.country_name - e_country = self.game.red.country_name - self.mission.coalition["blue"].add_country( - country_dict[country_id_from_name(p_country)]() - ) - self.mission.coalition["red"].add_country( - country_dict[country_id_from_name(e_country)]() - ) - - belligerents = [ - country_id_from_name(p_country), - country_id_from_name(e_country), - ] - for country in country_dict.keys(): - if country not in belligerents: - self.mission.coalition["neutrals"].add_country(country_dict[country]()) - - def add_airfields_to_unit_map(self) -> None: - for control_point in self.game.theater.controlpoints: - if isinstance(control_point, Airfield): - self.unit_map.add_airfield(control_point) - - def initialize_registries(self) -> None: - unique_map_frequencies: set[RadioFrequency] = set() - self.initialize_tacan_registry(unique_map_frequencies) - self.initialize_radio_registry(unique_map_frequencies) - for frequency in unique_map_frequencies: - self.radio_registry.reserve(frequency) - - def initialize_tacan_registry( - self, unique_map_frequencies: set[RadioFrequency] - ) -> None: - """ - Dedup beacon/radio frequencies, since some maps have some frequencies - used multiple times. - """ - for beacon in Beacons.iter_theater(self.game.theater): - unique_map_frequencies.add(beacon.frequency) - if beacon.is_tacan: - if beacon.channel is None: - logging.warning(f"TACAN beacon has no channel: {beacon.callsign}") - else: - self.tacan_registry.mark_unavailable(beacon.tacan_channel) - - def initialize_radio_registry( - self, unique_map_frequencies: set[RadioFrequency] - ) -> None: - for airport in self.game.theater.terrain.airport_list(): - if (atc := AtcData.from_pydcs(airport)) is not None: - unique_map_frequencies.add(atc.hf) - unique_map_frequencies.add(atc.vhf_fm) - unique_map_frequencies.add(atc.vhf_am) - unique_map_frequencies.add(atc.uhf) - # No need to reserve ILS or TACAN because those are in the - # beacon list. - - def _find_combat_groups_between( - self, - planners: dict[ControlPoint, GroundPlanner], - origin: ControlPoint, - target: ControlPoint, - ) -> list[CombatGroup]: - try: - planner = planners[origin] - except KeyError as ex: - raise KeyError(f"No ground planner found at {origin}") from ex - - try: - return planner.units_per_cp[target.id] - except KeyError as ex: - raise KeyError( - f"Ground planner at {origin} does not target {target}" - ) from ex - - def generate_ground_conflicts(self) -> None: - """Generate FLOTs and JTACs for each active front line.""" - planners: dict[ControlPoint, GroundPlanner] = {} - for control_point in self.game.theater.controlpoints: - if control_point.has_frontline: - planner = GroundPlanner(control_point, self.game) - planners[control_point] = planner - planner.plan_groundwar() - - for front_line in self.game.theater.conflicts(): - player_cp = front_line.blue_cp - enemy_cp = front_line.red_cp - conflict = FrontLineConflictDescription.frontline_cas_conflict( - front_line, self.game.theater - ) - # Generate frontline ops - ground_conflict_gen = FlotGenerator( - self.mission, - conflict, - self.game, - self._find_combat_groups_between(planners, player_cp, enemy_cp), - self._find_combat_groups_between(planners, enemy_cp, player_cp), - player_cp.stances[enemy_cp.id], - enemy_cp.stances[player_cp.id], - self.unit_map, - self.radio_registry, - self.mission_data, - ) - ground_conflict_gen.generate() - - def generate_air_units(self, tgo_generator: TgoGenerator) -> None: - """Generate the air units for the Operation""" - - # Air Support (Tanker & Awacs) - air_support_generator = AirSupportGenerator( - self.mission, - AirConflictDescription.for_theater(self.game.theater), - self.game, - self.radio_registry, - self.tacan_registry, - self.mission_data, - ) - air_support_generator.generate() - - # Generate Aircraft Activity on the map - aircraft_generator = AircraftGenerator( - self.mission, - self.game.settings, - self.game, - self.time, - self.radio_registry, - self.tacan_registry, - self.unit_map, - mission_data=air_support_generator.mission_data, - helipads=tgo_generator.helipads, - ) - - aircraft_generator.clear_parking_slots() - - aircraft_generator.generate_flights( - self.mission.country(self.game.blue.country_name), - self.game.blue.ato, - tgo_generator.runways, - ) - aircraft_generator.generate_flights( - self.mission.country(self.game.red.country_name), - self.game.red.ato, - tgo_generator.runways, - ) - aircraft_generator.spawn_unused_aircraft( - self.mission.country(self.game.blue.country_name), - self.mission.country(self.game.red.country_name), - ) - - for package in aircraft_generator.briefing_data: - for flight in package: - if not flight.client_units: - continue - flight.aircraft_type.assign_channels_for_flight( - flight, air_support_generator.mission_data - ) - - self.mission_data.briefing_data = aircraft_generator.briefing_data - - def generate_destroyed_units(self) -> None: - """Add destroyed units to the Mission""" - if not self.game.settings.perf_destroyed_units: - return - - for d in self.game.get_destroyed_units(): - try: - type_name = d["type"] - if not isinstance(type_name, str): - raise TypeError( - "Expected the type of the destroyed static to be a string" - ) - utype = unit_type_from_name(type_name) - except KeyError: - logging.warning(f"Destroyed unit has no type: {d}") - continue - - pos = Point(cast(float, d["x"]), cast(float, d["z"]), self.mission.terrain) - if utype is not None and not self.game.position_culled(pos): - self.mission.static_group( - country=self.mission.country(self.game.blue.country_name), - name="", - _type=utype, - hidden=True, - position=pos, - heading=d["orientation"], - dead=True, - ) - - def notify_info_generators( - self, - ) -> None: - """Generates subscribed MissionInfoGenerator objects.""" - mission_data = self.mission_data - gens: list[MissionInfoGenerator] = [ - KneeboardGenerator(self.mission, self.game), - BriefingGenerator(self.mission, self.game), - ] - for gen in gens: - for dynamic_runway in mission_data.runways: - gen.add_dynamic_runway(dynamic_runway) - - for tanker in mission_data.tankers: - if tanker.blue: - gen.add_tanker(tanker) - - for aewc in mission_data.awacs: - if aewc.blue: - gen.add_awacs(aewc) - - for jtac in mission_data.jtacs: - if jtac.blue: - gen.add_jtac(jtac) - - for package in mission_data.briefing_data: - gen.add_package_briefing_data(package) - gen.generate() - - def setup_combined_arms(self) -> None: - self.mission.groundControl.blue_game_masters = ( - self.game.settings.game_master_slots - ) - self.mission.groundControl.blue_tactical_commander = ( - self.game.settings.tactical_commander_slots - ) - self.mission.groundControl.pilot_can_control_vehicles = ( - self.mission.groundControl.blue_tactical_commander > 0 - ) - self.mission.groundControl.blue_jtac = self.game.settings.jtac_operator_slots - self.mission.groundControl.blue_observer = self.game.settings.observer_slots diff --git a/game/missiongenerator/tgogenerator.py b/game/missiongenerator/tgogenerator.py deleted file mode 100644 index 414e1778a..000000000 --- a/game/missiongenerator/tgogenerator.py +++ /dev/null @@ -1,730 +0,0 @@ -"""Generators for creating the groups for ground objectives. - -The classes in this file are responsible for creating the vehicle groups, ship -groups, statics, missile sites, and AA sites for the mission. Each of these -objectives is defined in the Theater by a TheaterGroundObject. These classes -create the pydcs groups and statics for those areas and add them to the mission. -""" -from __future__ import annotations - -import logging -import random -from typing import Any, Dict, Iterator, List, Optional, TYPE_CHECKING, Type - -import dcs.vehicles -from dcs import Mission, Point -from dcs.action import DoScript, SceneryDestructionZone -from dcs.condition import MapObjectIsDead -from dcs.country import Country -from dcs.ships import ( - CVN_71, - CVN_72, - CVN_73, - CVN_75, - Stennis, -) -from dcs.statics import Fortification -from dcs.task import ( - ActivateACLSCommand, - ActivateBeaconCommand, - ActivateICLSCommand, - ActivateLink4Command, - EPLRS, - FireAtPoint, - OptAlarmState, -) -from dcs.translation import String -from dcs.triggers import ( - Event, - TriggerOnce, - TriggerStart, - TriggerZone, - TriggerZoneCircular, - TriggerZoneQuadPoint, -) -from dcs.unit import InvisibleFARP, Unit -from dcs.unitgroup import MovingGroup, ShipGroup, StaticGroup, VehicleGroup -from dcs.unittype import ShipType, VehicleType -from dcs.vehicles import vehicle_map - -from game.missiongenerator.missiondata import CarrierInfo, MissionData -from game.radio.radios import RadioFrequency, RadioRegistry -from game.radio.tacan import TacanBand, TacanChannel, TacanRegistry, TacanUsage -from game.runways import RunwayData -from game.theater import ControlPoint, TheaterGroundObject, TheaterUnit -from game.theater.theatergroundobject import ( - CarrierGroundObject, - GenericCarrierGroundObject, - LhaGroundObject, - MissileSiteGroundObject, -) -from game.theater.theatergroup import IadsGroundGroup, SceneryUnit -from game.unitmap import UnitMap -from game.utils import Heading, feet, knots, mps - -if TYPE_CHECKING: - from game import Game - -FARP_FRONTLINE_DISTANCE = 10000 -AA_CP_MIN_DISTANCE = 40000 - - -class GroundObjectGenerator: - """generates the DCS groups and units from the TheaterGroundObject""" - - def __init__( - self, - ground_object: TheaterGroundObject, - country: Country, - game: Game, - mission: Mission, - unit_map: UnitMap, - ) -> None: - self.ground_object = ground_object - self.country = country - self.game = game - self.m = mission - self.unit_map = unit_map - - @property - def culled(self) -> bool: - return self.game.iads_considerate_culling(self.ground_object) - - def generate(self) -> None: - if self.culled: - return - for group in self.ground_object.groups: - vehicle_units = [] - ship_units = [] - # Split the different unit types to be compliant to dcs limitation - for unit in group.units: - if unit.is_static: - if isinstance(unit, SceneryUnit): - # Special handling for scenery objects - self.add_trigger_zone_for_scenery(unit) - if ( - self.game.lua_plugin_manager.is_plugin_enabled("skynetiads") - and self.game.theater.iads_network.advanced_iads - and isinstance(group, IadsGroundGroup) - and group.iads_role.participate - ): - # Generate a unit which can be controlled by skynet - self.generate_iads_command_unit(unit) - else: - # Create a static group for each static unit - self.create_static_group(unit) - elif unit.is_vehicle and unit.alive: - # All alive Vehicles - vehicle_units.append(unit) - elif unit.is_ship and unit.alive: - # All alive Ships - ship_units.append(unit) - if vehicle_units: - self.create_vehicle_group(group.group_name, vehicle_units) - if ship_units: - self.create_ship_group(group.group_name, ship_units) - - def create_vehicle_group( - self, group_name: str, units: list[TheaterUnit] - ) -> VehicleGroup: - vehicle_group: Optional[VehicleGroup] = None - for unit in units: - assert issubclass(unit.type, VehicleType) - if vehicle_group is None: - vehicle_group = self.m.vehicle_group( - self.country, - group_name, - unit.type, - position=unit.position, - heading=unit.position.heading.degrees, - ) - vehicle_group.units[0].player_can_drive = True - self.enable_eplrs(vehicle_group, unit.type) - vehicle_group.units[0].name = unit.unit_name - self.set_alarm_state(vehicle_group) - else: - vehicle_unit = self.m.vehicle(unit.unit_name, unit.type) - vehicle_unit.player_can_drive = True - vehicle_unit.position = unit.position - vehicle_unit.heading = unit.position.heading.degrees - vehicle_group.add_unit(vehicle_unit) - self._register_theater_unit(vehicle_group.id, unit, vehicle_group.units[-1]) - if vehicle_group is None: - raise RuntimeError(f"Error creating VehicleGroup for {group_name}") - return vehicle_group - - def create_ship_group( - self, - group_name: str, - units: list[TheaterUnit], - frequency: Optional[RadioFrequency] = None, - ) -> ShipGroup: - ship_group: Optional[ShipGroup] = None - for unit in units: - assert issubclass(unit.type, ShipType) - if ship_group is None: - ship_group = self.m.ship_group( - self.country, - group_name, - unit.type, - position=unit.position, - heading=unit.position.heading.degrees, - ) - if frequency: - ship_group.set_frequency(frequency.hertz) - ship_group.units[0].name = unit.unit_name - self.set_alarm_state(ship_group) - else: - ship_unit = self.m.ship(unit.unit_name, unit.type) - if frequency: - ship_unit.set_frequency(frequency.hertz) - ship_unit.position = unit.position - ship_unit.heading = unit.position.heading.degrees - ship_group.add_unit(ship_unit) - self._register_theater_unit(ship_group.id, unit, ship_group.units[-1]) - if ship_group is None: - raise RuntimeError(f"Error creating ShipGroup for {group_name}") - return ship_group - - def create_static_group(self, unit: TheaterUnit) -> None: - static_group = self.m.static_group( - country=self.country, - name=unit.unit_name, - _type=unit.type, - position=unit.position, - heading=unit.position.heading.degrees, - dead=not unit.alive, - ) - self._register_theater_unit(static_group.id, unit, static_group.units[0]) - - @staticmethod - def enable_eplrs(group: VehicleGroup, unit_type: Type[VehicleType]) -> None: - if unit_type.eplrs: - group.points[0].tasks.append(EPLRS(group.id)) - - def set_alarm_state(self, group: MovingGroup[Any]) -> None: - if self.game.settings.perf_red_alert_state: - group.points[0].tasks.append(OptAlarmState(2)) - else: - group.points[0].tasks.append(OptAlarmState(1)) - - def _register_theater_unit( - self, - dcs_group_id: int, - theater_unit: TheaterUnit, - dcs_unit: Unit, - ) -> None: - self.unit_map.add_theater_unit_mapping(dcs_group_id, theater_unit, dcs_unit) - - def add_trigger_zone_for_scenery(self, scenery: SceneryUnit) -> None: - # Align the trigger zones to the faction color on the DCS briefing/F10 map. - color = ( - {1: 0.2, 2: 0.7, 3: 1, 4: 0.15} - if scenery.ground_object.is_friendly(to_player=True) - else {1: 1, 2: 0.2, 3: 0.2, 4: 0.15} - ) - - trigger_zone: TriggerZone - if isinstance(scenery.zone, TriggerZoneCircular): - trigger_zone = self.create_circular_scenery_trigger(scenery.zone, color) - elif isinstance(scenery.zone, TriggerZoneQuadPoint): - trigger_zone = self.create_quad_scenery_trigger(scenery.zone, color) - else: - raise ValueError( - f"Invalid trigger zone type found for {scenery.name} in " - f"{self.ground_object.name}: {scenery.zone.__class__.__name__}" - ) - - # DCS only visually shows a scenery object is dead when - # this trigger rule is applied. Otherwise you can kill a - # structure twice. - if not scenery.alive: - self.generate_destruction_trigger_rule(trigger_zone) - else: - self.generate_on_dead_trigger_rule(trigger_zone) - - self.unit_map.add_scenery(scenery, trigger_zone) - - def create_circular_scenery_trigger( - self, zone: TriggerZoneCircular, color: dict[int, float] - ) -> TriggerZoneCircular: - # Create the smallest valid size trigger zone (16 feet) so that risk of overlap - # is minimized. As long as the triggerzone is over the scenery object, we're ok. - smallest_valid_radius = feet(16).meters - - return self.m.triggers.add_triggerzone( - zone.position, - smallest_valid_radius, - zone.hidden, - zone.name, - color, - zone.properties, - ) - - def create_quad_scenery_trigger( - self, zone: TriggerZoneQuadPoint, color: dict[int, float] - ) -> TriggerZoneQuadPoint: - return self.m.triggers.add_triggerzone_quad( - zone.position, - zone.verticies, - zone.hidden, - zone.name, - color, - zone.properties, - ) - - def generate_destruction_trigger_rule(self, trigger_zone: TriggerZone) -> None: - # Add destruction zone trigger - t = TriggerStart(comment="Destruction") - t.actions.append( - SceneryDestructionZone(destruction_level=100, zone=trigger_zone.id) - ) - self.m.triggerrules.triggers.append(t) - - def generate_on_dead_trigger_rule(self, trigger_zone: TriggerZone) -> None: - # Add a TriggerRule with the MapObjectIsDead condition to recognize killed - # map objects and add them to the state.json with a DoScript - t = TriggerOnce(Event.NoEvent, f"MapObjectIsDead Trigger {trigger_zone.id}") - t.add_condition(MapObjectIsDead(trigger_zone.id)) - script_string = String( - f'killed_ground_units[#killed_ground_units + 1] = "{trigger_zone.name}"' - ) - t.actions.append(DoScript(script_string)) - self.m.triggerrules.triggers.append(t) - - def generate_iads_command_unit(self, unit: SceneryUnit) -> None: - # Creates a static Unit (tyre with red flag) next to a scenery object. This is - # needed because skynet can not use map objects as Comms, Power or Command and - # needs a "real" unit to function correctly - self.m.static_group( - country=self.country, - name=unit.unit_name, - _type=dcs.statics.Fortification.Black_Tyre_RF, - position=unit.position, - heading=unit.position.heading.degrees, - dead=not unit.alive, # Also spawn as dead! - ) - - -class MissileSiteGenerator(GroundObjectGenerator): - @property - def culled(self) -> bool: - # Don't cull missile sites - their range is long enough to make them easily - # culled despite being a threat. - return False - - def generate(self) -> None: - super(MissileSiteGenerator, self).generate() - - if not self.game.settings.generate_fire_tasks_for_missile_sites: - return - - # Note : Only the SCUD missiles group can fire (V1 site cannot fire in game right now) - # TODO : Should be pre-planned ? - # TODO : Add delay to task to spread fire task over mission duration ? - for group in self.ground_object.groups: - vg = self.m.find_group(group.group_name) - if vg is not None: - targets = self.possible_missile_targets() - if targets: - target = random.choice(targets) - real_target = target.point_from_heading( - Heading.random().degrees, random.randint(0, 2500) - ) - vg.points[0].add_task(FireAtPoint(real_target)) - logging.info("Set up fire task for missile group.") - else: - logging.info( - "Couldn't setup missile site to fire, no valid target in range." - ) - else: - logging.info( - "Couldn't setup missile site to fire, group was not generated." - ) - - def possible_missile_targets(self) -> List[Point]: - """ - Find enemy control points in range - :return: List of possible missile targets - """ - targets: List[Point] = [] - for cp in self.game.theater.controlpoints: - if cp.captured != self.ground_object.control_point.captured: - distance = cp.position.distance_to_point(self.ground_object.position) - if distance < self.missile_site_range: - targets.append(cp.position) - return targets - - @property - def missile_site_range(self) -> int: - """ - Get the missile site range - :return: Missile site range - """ - site_range = 0 - for group in self.ground_object.groups: - vg = self.m.find_group(group.group_name) - if vg is not None: - for u in vg.units: - if u.type in vehicle_map: - if vehicle_map[u.type].threat_range > site_range: - site_range = vehicle_map[u.type].threat_range - return site_range - - -class GenericCarrierGenerator(GroundObjectGenerator): - """Base type for carrier group generation. - - Used by both CV(N) groups and LHA groups. - """ - - def __init__( - self, - ground_object: GenericCarrierGroundObject, - control_point: ControlPoint, - country: Country, - game: Game, - mission: Mission, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - icls_alloc: Iterator[int], - runways: Dict[str, RunwayData], - unit_map: UnitMap, - mission_data: MissionData, - ) -> None: - super().__init__(ground_object, country, game, mission, unit_map) - self.ground_object = ground_object - self.control_point = control_point - self.radio_registry = radio_registry - self.tacan_registry = tacan_registry - self.icls_alloc = icls_alloc - self.runways = runways - self.mission_data = mission_data - - def generate(self) -> None: - # This can also be refactored as the general generation was updated - atc = self.radio_registry.alloc_uhf() - - for g_id, group in enumerate(self.ground_object.groups): - if not group.units: - logging.warning(f"Found empty carrier group in {self.control_point}") - continue - - ship_units = [] - for unit in group.units: - if unit.alive: - # All alive Ships - ship_units.append(unit) - - if not ship_units: - # No alive units in this group, continue with next group - continue - - ship_group = self.create_ship_group(group.group_name, ship_units, atc) - - # Always steam into the wind, even if the carrier is being moved. - # There are multiple unsimulated hours between turns, so we can - # count those as the time the carrier uses to move and the mission - # time as the recovery window. - brc = self.steam_into_wind(ship_group) - - # Set Carrier Specific Options - if g_id == 0 and self.control_point.runway_is_operational(): - # Get Correct unit type for the carrier. - # This will upgrade to super carrier if option is enabled - carrier_type = self.carrier_type - if carrier_type is None: - raise RuntimeError( - f"Error generating carrier group for {self.control_point.name}" - ) - ship_group.units[0].type = carrier_type.id - tacan = self.tacan_registry.alloc_for_band( - TacanBand.X, TacanUsage.TransmitReceive - ) - tacan_callsign = self.tacan_callsign() - icls = next(self.icls_alloc) - link4 = None - if carrier_type in [Stennis, CVN_71, CVN_72, CVN_73, CVN_75]: - link4 = self.radio_registry.alloc_link4() - self.activate_beacons(ship_group, tacan, tacan_callsign, icls, link4) - self.add_runway_data( - brc or Heading.from_degrees(0), atc, tacan, tacan_callsign, icls - ) - self.mission_data.carriers.append( - CarrierInfo( - group_name=ship_group.name, - unit_name=ship_group.units[0].name, - callsign=tacan_callsign, - freq=atc, - tacan=tacan, - blue=self.control_point.captured, - ) - ) - - @property - def carrier_type(self) -> Optional[Type[ShipType]]: - return self.control_point.get_carrier_group_type() - - def steam_into_wind(self, group: ShipGroup) -> Optional[Heading]: - wind = self.game.conditions.weather.wind.at_0m - brc = Heading.from_degrees(wind.direction).opposite - # Aim for 25kts over the deck. - carrier_speed = knots(25) - mps(wind.speed) - for attempt in range(5): - point = group.points[0].position.point_from_heading( - brc.degrees, 100000 - attempt * 20000 - ) - if self.game.theater.is_in_sea(point): - group.points[0].speed = carrier_speed.meters_per_second - group.add_waypoint(point, carrier_speed.kph) - # Rotate the whole ground object to the new course - self.ground_object.rotate(brc) - return brc - return None - - def tacan_callsign(self) -> str: - raise NotImplementedError - - @staticmethod - def activate_beacons( - group: ShipGroup, - tacan: TacanChannel, - callsign: str, - icls: int, - link4: Optional[RadioFrequency] = None, - ) -> None: - group.points[0].tasks.append( - ActivateBeaconCommand( - channel=tacan.number, - modechannel=tacan.band.value, - callsign=callsign, - unit_id=group.units[0].id, - aa=False, - ) - ) - group.points[0].tasks.append( - ActivateICLSCommand(icls, unit_id=group.units[0].id) - ) - if link4 is not None: - group.points[0].tasks.append( - ActivateLink4Command(int(link4.mhz), group.units[0].id) - ) - group.points[0].tasks.append(ActivateACLSCommand(unit_id=group.units[0].id)) - - def add_runway_data( - self, - brc: Heading, - atc: RadioFrequency, - tacan: TacanChannel, - callsign: str, - icls: int, - ) -> None: - # TODO: Make unit name usable. - # This relies on one control point mapping exactly - # to one LHA, carrier, or other usable "runway". - # This isn't wholly true, since the DD escorts of - # the carrier group are valid for helicopters, but - # they aren't exposed as such to the game. Should - # clean this up so that's possible. We can't use the - # unit name since it's an arbitrary ID. - self.runways[self.control_point.name] = RunwayData( - self.control_point.name, - brc, - "N/A", - atc=atc, - tacan=tacan, - tacan_callsign=callsign, - icls=icls, - ) - - -class CarrierGenerator(GenericCarrierGenerator): - """Generator for CV(N) groups.""" - - def tacan_callsign(self) -> str: - # TODO: Assign these properly. - return random.choice( - [ - "STE", - "CVN", - "CVH", - "CCV", - "ACC", - "ARC", - "GER", - "ABR", - "LIN", - "TRU", - ] - ) - - -class LhaGenerator(GenericCarrierGenerator): - """Generator for LHA groups.""" - - def tacan_callsign(self) -> str: - # TODO: Assign these properly. - return random.choice( - [ - "LHD", - "LHA", - "LHB", - "LHC", - "LHD", - "LDS", - ] - ) - - -class HelipadGenerator: - """ - Generates helipads for given control point - """ - - def __init__( - self, - mission: Mission, - cp: ControlPoint, - game: Game, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - ): - self.m = mission - self.cp = cp - self.game = game - self.radio_registry = radio_registry - self.tacan_registry = tacan_registry - self.helipads: Optional[StaticGroup] = None - - def generate(self) -> None: - # This gets called for every control point, so we don't want to add an empty group (causes DCS mission editor to crash) - if len(self.cp.helipads) == 0: - return - # Note: Helipad are generated as neutral object in order not to interfer with - # capture triggers - country = self.m.country(self.game.coalition_for(self.cp.captured).country_name) - - for i, helipad in enumerate(self.cp.helipads): - heading = helipad.heading.degrees - name_i = self.cp.name + "_helipad" + "_" + str(i) - if self.helipads is None: - self.helipads = self.m.farp( - self.m.country(self.game.neutral_country.name), - name_i, - helipad, - farp_type="InvisibleFARP", - ) - else: - # Create a new Helipad Unit - self.helipads.add_unit( - InvisibleFARP(self.m.terrain, self.m.next_unit_id(), name_i) - ) - pad = self.helipads.units[-1] - pad.position = helipad - pad.heading = heading - # Generate a FARP Ammo and Fuel stack for each pad - self.m.static_group( - country=country, - name=(name_i + "_fuel"), - _type=Fortification.FARP_Fuel_Depot, - position=helipad.point_from_heading(heading, 35), - heading=heading, - ) - self.m.static_group( - country=country, - name=(name_i + "_ammo"), - _type=Fortification.FARP_Ammo_Dump_Coating, - position=helipad.point_from_heading(heading, 35).point_from_heading( - heading + 90, 10 - ), - heading=heading, - ) - self.m.static_group( - country=country, - name=(name_i + "_ws"), - _type=Fortification.Windsock, - position=helipad.point_from_heading(heading + 45, 35), - heading=heading, - ) - - -class TgoGenerator: - """Creates DCS groups and statics for the theater during mission generation. - - Most of the work of group/static generation is delegated to the other - generator classes. This class is responsible for finding each of the - locations for spawning ground objects, determining their types, and creating - the appropriate generators. - """ - - def __init__( - self, - mission: Mission, - game: Game, - radio_registry: RadioRegistry, - tacan_registry: TacanRegistry, - unit_map: UnitMap, - mission_data: MissionData, - ) -> None: - self.m = mission - self.game = game - self.radio_registry = radio_registry - self.tacan_registry = tacan_registry - self.unit_map = unit_map - self.icls_alloc = iter(range(1, 21)) - self.runways: Dict[str, RunwayData] = {} - self.helipads: dict[ControlPoint, StaticGroup] = {} - self.mission_data = mission_data - - def generate(self) -> None: - for cp in self.game.theater.controlpoints: - country = self.m.country(self.game.coalition_for(cp.captured).country_name) - - # Generate helipads - helipad_gen = HelipadGenerator( - self.m, cp, self.game, self.radio_registry, self.tacan_registry - ) - helipad_gen.generate() - if helipad_gen.helipads is not None: - self.helipads[cp] = helipad_gen.helipads - - for ground_object in cp.ground_objects: - generator: GroundObjectGenerator - if isinstance(ground_object, CarrierGroundObject): - generator = CarrierGenerator( - ground_object, - cp, - country, - self.game, - self.m, - self.radio_registry, - self.tacan_registry, - self.icls_alloc, - self.runways, - self.unit_map, - self.mission_data, - ) - elif isinstance(ground_object, LhaGroundObject): - generator = LhaGenerator( - ground_object, - cp, - country, - self.game, - self.m, - self.radio_registry, - self.tacan_registry, - self.icls_alloc, - self.runways, - self.unit_map, - self.mission_data, - ) - elif isinstance(ground_object, MissileSiteGroundObject): - generator = MissileSiteGenerator( - ground_object, country, self.game, self.m, self.unit_map - ) - else: - generator = GroundObjectGenerator( - ground_object, country, self.game, self.m, self.unit_map - ) - generator.generate() - self.mission_data.runways = list(self.runways.values()) diff --git a/game/missiongenerator/triggergenerator.py b/game/missiongenerator/triggergenerator.py deleted file mode 100644 index 25a874825..000000000 --- a/game/missiongenerator/triggergenerator.py +++ /dev/null @@ -1,211 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from dcs.action import ClearFlag, DoScript, MarkToAll, SetFlag -from dcs.condition import ( - AllOfCoalitionOutsideZone, - FlagIsFalse, - FlagIsTrue, - PartOfCoalitionInZone, - TimeAfter, -) -from dcs.mission import Mission -from dcs.task import Option -from dcs.translation import String -from dcs.triggers import Event, TriggerCondition, TriggerOnce -from dcs.unit import Skill - -from game.theater import Airfield -from game.theater.controlpoint import Fob - -if TYPE_CHECKING: - from game.game import Game - -PUSH_TRIGGER_SIZE = 3000 -PUSH_TRIGGER_ACTIVATION_AGL = 25 - -REGROUP_ZONE_DISTANCE = 12000 -REGROUP_ALT = 5000 - -TRIGGER_WAYPOINT_OFFSET = 2 -TRIGGER_MIN_DISTANCE_FROM_START = 10000 -# modified since we now have advanced SAM units -TRIGGER_RADIUS_MINIMUM = 3000000 - -TRIGGER_RADIUS_SMALL = 50000 -TRIGGER_RADIUS_MEDIUM = 100000 -TRIGGER_RADIUS_LARGE = 150000 -TRIGGER_RADIUS_ALL_MAP = 3000000 - - -class Silence(Option): - Key = 7 - - -class TriggerGenerator: - capture_zone_types = (Fob, Airfield) - capture_zone_flag = 600 - - def __init__(self, mission: Mission, game: Game) -> None: - self.mission = mission - self.game = game - - def _set_allegiances(self, player_coalition: str, enemy_coalition: str) -> None: - """ - Set airbase initial coalition - """ - - # Empty neutrals airports - airfields = [ - cp for cp in self.game.theater.controlpoints if isinstance(cp, Airfield) - ] - airport_ids = {cp.airport.id for cp in airfields} - for airport in self.mission.terrain.airport_list(): - if airport.id not in airport_ids: - airport.unlimited_fuel = False - airport.unlimited_munitions = False - airport.unlimited_aircrafts = False - airport.gasoline_init = 0 - airport.methanol_mixture_init = 0 - airport.diesel_init = 0 - airport.jet_init = 0 - airport.operating_level_air = 0 - airport.operating_level_equipment = 0 - airport.operating_level_fuel = 0 - - for airport in self.mission.terrain.airport_list(): - if airport.id not in airport_ids: - airport.unlimited_fuel = True - airport.unlimited_munitions = True - airport.unlimited_aircrafts = True - - for airfield in airfields: - cp_airport = self.mission.terrain.airport_by_id(airfield.airport.id) - if cp_airport is None: - raise RuntimeError( - f"Could not find {airfield.airport.name} in the mission" - ) - cp_airport.set_coalition( - airfield.captured and player_coalition or enemy_coalition - ) - - def _set_skill(self, player_coalition: str, enemy_coalition: str) -> None: - """ - Set skill level for all aircraft in the mission - """ - for coalition_name, coalition in self.mission.coalition.items(): - if coalition_name == player_coalition: - skill_level = Skill(self.game.settings.player_skill) - elif coalition_name == enemy_coalition: - skill_level = Skill(self.game.settings.enemy_vehicle_skill) - else: - continue - - for country in coalition.countries.values(): - for vehicle_group in country.vehicle_group: - vehicle_group.set_skill(skill_level) - - def _gen_markers(self) -> None: - """ - Generate markers on F10 map for each existing objective - """ - if self.game.settings.generate_marks: - mark_trigger = TriggerOnce(Event.NoEvent, "Marks generator") - mark_trigger.add_condition(TimeAfter(1)) - v = 10 - for cp in self.game.theater.controlpoints: - seen = set() - for ground_object in cp.ground_objects: - if ground_object.obj_name in seen: - continue - - seen.add(ground_object.obj_name) - for location in ground_object.mark_locations: - zone = self.mission.triggers.add_triggerzone( - location, radius=10, hidden=True, name="MARK" - ) - if cp.captured: - name = ground_object.obj_name + " [ALLY]" - else: - name = ground_object.obj_name + " [ENEMY]" - mark_trigger.add_action(MarkToAll(v, zone.id, String(name))) - v += 1 - self.mission.triggerrules.triggers.append(mark_trigger) - - def _generate_capture_triggers( - self, player_coalition: str, enemy_coalition: str - ) -> None: - """Creates a pair of triggers for each control point of `cls.capture_zone_types`. - One for the initial capture of a control point, and one if it is recaptured. - Directly appends to the global `base_capture_events` var declared by `dcs_libaration.lua` - """ - for cp in self.game.theater.controlpoints: - if isinstance(cp, self.capture_zone_types): - if cp.captured: - attacking_coalition = enemy_coalition - attack_coalition_int = 1 # 1 is the Event int for Red - defending_coalition = player_coalition - defend_coalition_int = 2 # 2 is the Event int for Blue - else: - attacking_coalition = player_coalition - attack_coalition_int = 2 - defending_coalition = enemy_coalition - defend_coalition_int = 1 - - trigger_zone = self.mission.triggers.add_triggerzone( - cp.position, radius=3000, hidden=False, name="CAPTURE" - ) - flag = self.get_capture_zone_flag() - capture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger") - capture_trigger.add_condition( - AllOfCoalitionOutsideZone( - defending_coalition, trigger_zone.id, unit_type="GROUND" - ) - ) - capture_trigger.add_condition( - PartOfCoalitionInZone( - attacking_coalition, trigger_zone.id, unit_type="GROUND" - ) - ) - capture_trigger.add_condition(FlagIsFalse(flag=flag)) - script_string = String( - f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{attack_coalition_int}||{cp.full_name}"' - ) - capture_trigger.add_action(DoScript(script_string)) - capture_trigger.add_action(SetFlag(flag=flag)) - self.mission.triggerrules.triggers.append(capture_trigger) - - recapture_trigger = TriggerCondition(Event.NoEvent, "Capture Trigger") - recapture_trigger.add_condition( - AllOfCoalitionOutsideZone( - attacking_coalition, trigger_zone.id, unit_type="GROUND" - ) - ) - recapture_trigger.add_condition( - PartOfCoalitionInZone( - defending_coalition, trigger_zone.id, unit_type="GROUND" - ) - ) - recapture_trigger.add_condition(FlagIsTrue(flag=flag)) - script_string = String( - f'base_capture_events[#base_capture_events + 1] = "{cp.id}||{defend_coalition_int}||{cp.full_name}"' - ) - recapture_trigger.add_action(DoScript(script_string)) - recapture_trigger.add_action(ClearFlag(flag=flag)) - self.mission.triggerrules.triggers.append(recapture_trigger) - - def generate(self) -> None: - player_coalition = "blue" - enemy_coalition = "red" - - self._set_skill(player_coalition, enemy_coalition) - self._set_allegiances(player_coalition, enemy_coalition) - self._gen_markers() - self._generate_capture_triggers(player_coalition, enemy_coalition) - - @classmethod - def get_capture_zone_flag(cls) -> int: - flag = cls.capture_zone_flag - cls.capture_zone_flag += 1 - return flag diff --git a/game/missiongenerator/visualsgenerator.py b/game/missiongenerator/visualsgenerator.py deleted file mode 100644 index 14aa5af3c..000000000 --- a/game/missiongenerator/visualsgenerator.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -import random -from typing import Any, TYPE_CHECKING - -from dcs.mission import Mission -from dcs.unit import Static -from dcs.unittype import StaticType - -if TYPE_CHECKING: - from game import Game - -from .frontlineconflictdescription import FrontLineConflictDescription - - -class MarkerSmoke(StaticType): - id = "big_smoke" - category = "Effects" - name = "big_smoke" - shape_name = 5 # type: ignore - rate = 0.1 # type: ignore - - -class Smoke(StaticType): - id = "big_smoke" - category = "Effects" - name = "big_smoke" - shape_name = 2 # type: ignore - rate = 1 - - -class BigSmoke(StaticType): - id = "big_smoke" - category = "Effects" - name = "big_smoke" - shape_name = 3 # type: ignore - rate = 1 - - -class MassiveSmoke(StaticType): - id = "big_smoke" - category = "Effects" - name = "big_smoke" - shape_name = 4 # type: ignore - rate = 1 - - -def __monkey_static_dict(self: Static) -> dict[str, Any]: - global __original_static_dict - - d = __original_static_dict(self) - if self.type == "big_smoke": - d["effectPreset"] = self.shape_name - d["effectTransparency"] = self.rate - return d - - -__original_static_dict = Static.dict -Static.dict = __monkey_static_dict # type: ignore - -FRONT_SMOKE_RANDOM_SPREAD = 4000 -FRONT_SMOKE_TYPE_CHANCES = { - 2: MassiveSmoke, - 15: BigSmoke, - 30: Smoke, - 100: Smoke, -} - - -class VisualsGenerator: - def __init__(self, mission: Mission, game: Game) -> None: - self.mission = mission - self.game = game - - def _generate_frontline_smokes(self) -> None: - for front_line in self.game.theater.conflicts(): - from_cp = front_line.blue_cp - to_cp = front_line.red_cp - if from_cp.is_global or to_cp.is_global: - continue - - bounds = FrontLineConflictDescription.frontline_bounds( - front_line, self.game.theater - ) - - for offset in range( - 0, bounds.length, self.game.settings.perf_smoke_spacing - ): - position = bounds.left_position.point_from_heading( - bounds.heading_from_left_to_right.degrees, offset - ) - - for k, v in FRONT_SMOKE_TYPE_CHANCES.items(): - if random.randint(0, 100) <= k: - pos = position.random_point_within( - FRONT_SMOKE_RANDOM_SPREAD, FRONT_SMOKE_RANDOM_SPREAD - ) - if not self.game.theater.is_on_land(pos): - break - - self.mission.static_group( - self.mission.country(self.game.red.country_name), - "", - _type=v, - position=pos, - ) - break - - def generate(self) -> None: - if self.game.settings.perf_smoke_gen: - self._generate_frontline_smokes() diff --git a/game/models/game_stats.py b/game/models/game_stats.py deleted file mode 100644 index 780565d43..000000000 --- a/game/models/game_stats.py +++ /dev/null @@ -1,67 +0,0 @@ -from __future__ import annotations - -from typing import List, TYPE_CHECKING - -if TYPE_CHECKING: - from game import Game - - -class FactionTurnMetadata: - """ - Store metadata about a faction - """ - - aircraft_count: int = 0 - vehicles_count: int = 0 - sam_count: int = 0 - - def __init__(self) -> None: - self.aircraft_count = 0 - self.vehicles_count = 0 - self.sam_count = 0 - - -class GameTurnMetadata: - """ - Store metadata about a game turn - """ - - allied_units: FactionTurnMetadata - enemy_units: FactionTurnMetadata - - def __init__(self) -> None: - self.allied_units = FactionTurnMetadata() - self.enemy_units = FactionTurnMetadata() - - -class GameStats: - """ - Store statistics for the current game - """ - - def __init__(self) -> None: - self.data_per_turn: List[GameTurnMetadata] = [] - - def update(self, game: Game) -> None: - """ - Save data for current turn - :param game: Game we want to save the data about - """ - - # Remove the current turn if its just an update for this turn - if 0 < game.turn < len(self.data_per_turn): - del self.data_per_turn[-1] - - turn_data = GameTurnMetadata() - - for cp in game.theater.controlpoints: - if cp.captured: - for squadron in cp.squadrons: - turn_data.allied_units.aircraft_count += squadron.owned_aircraft - turn_data.allied_units.vehicles_count += sum(cp.base.armor.values()) - else: - for squadron in cp.squadrons: - turn_data.enemy_units.aircraft_count += squadron.owned_aircraft - turn_data.enemy_units.vehicles_count += sum(cp.base.armor.values()) - - self.data_per_turn.append(turn_data) diff --git a/game/modsupport.py b/game/modsupport.py deleted file mode 100644 index a5413e3f3..000000000 --- a/game/modsupport.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Type - -from dcs.helicopters import HelicopterType, helicopter_map -from dcs.planes import PlaneType, plane_map -from dcs.unittype import VehicleType -from dcs.vehicles import vehicle_map - - -def helicoptermod(helicopter: Type[HelicopterType]) -> Type[HelicopterType]: - helicopter_map[helicopter.id] = helicopter - return helicopter - - -def planemod(plane: Type[PlaneType]) -> Type[PlaneType]: - plane_map[plane.id] = plane - return plane - - -def vehiclemod(vehicle: Type[VehicleType]) -> Type[VehicleType]: - vehicle_map[vehicle.id] = vehicle - return vehicle diff --git a/game/naming.py b/game/naming.py deleted file mode 100644 index 4a663ab42..000000000 --- a/game/naming.py +++ /dev/null @@ -1,562 +0,0 @@ -from __future__ import annotations - -import random -import time -from typing import Any, List, TYPE_CHECKING - -from dcs.country import Country - -from game.dcs.aircrafttype import AircraftType -from game.dcs.unittype import UnitType - -if TYPE_CHECKING: - from game.ato.flight import Flight - -ALPHA_MILITARY = [ - "Alpha", - "Bravo", - "Charlie", - "Delta", - "Echo", - "Foxtrot", - "Golf", - "Hotel", - "India", - "Juliet", - "Kilo", - "Lima", - "Mike", - "November", - "Oscar", - "Papa", - "Quebec", - "Romeo", - "Sierra", - "Tango", - "Uniform", - "Victor", - "Whisky", - "XRay", - "Yankee", - "Zulu", - "Zero", -] - -ANIMALS: tuple[str, ...] = ( - "AARDVARK", - "AARDWOLF", - "ADDER", - "ALBACORE", - "ALBATROSS", - "ALLIGATOR", - "ALPACA", - "ANACONDA", - "ANOLE", - "ANTEATER", - "ANTELOPE", - "ANTLION", - "ARAPAIMA", - "ARCHERFISH", - "ARGALI", - "ARMADILLO", - "ASP", - "AUROCHS", - "AXOLOTL", - "BABIRUSA", - "BABOON", - "BADGER", - "BANDICOOT", - "BARRACUDA", - "BARRAMUNDI", - "BASILISK", - "BASS", - "BAT", - "BEAR", - "BEAVER", - "BEETLE", - "BELUGA", - "BETTONG", - "BINTURONG", - "BISON", - "BLOODHOUND", - "BOA", - "BOBCAT", - "BONGO", - "BONITO", - "BUFFALO", - "BULLDOG", - "BULLFROG", - "BULLSHARK", - "BUMBLEBEE", - "BUNNY", - "BUTTERFLY", - "CAIMAN", - "CAMEL", - "CANARY", - "CAPYBARA", - "CARACAL", - "CARP", - "CASTOR", - "CAT", - "CATERPILLAR", - "CATFISH", - "CENTIPEDE", - "CHAMELEON", - "CHEETAH", - "CHICKEN", - "CHIMAERA", - "CICADA", - "CICHLID", - "CIVET", - "COBIA", - "COBRA", - "COCKATOO", - "COD", - "COELACANTH", - "COLT", - "CONDOR", - "COPPERHEAD", - "CORAL", - "CORGI", - "COTTONMOUTH", - "COUGAR", - "COW", - "COYOTE", - "CRAB", - "CRANE", - "CRICKET", - "CROCODILE", - "CROW", - "CUTTLEFISH", - "DACHSHUND", - "DEER", - "DINGO", - "DIREWOLF", - "DODO", - "DOG", - "DOLPHIN", - "DONKEY", - "DOVE", - "DRACO", - "DRAGON", - "DRAGONFLY", - "DUCK", - "DUGONG", - "EAGLE", - "EARWIG", - "ECHIDNA", - "EEL", - "ELEPHANT", - "ELK", - "EMU", - "ERMINE", - "FALCON", - "FANGTOOTH", - "FAWN", - "FENNEC", - "FERRET", - "FINCH", - "FIREFLY", - "FISH", - "FLAMINGO", - "FLEA", - "FLOUNDER", - "FOX", - "FRINGEHEAD", - "FROG", - "FROGMOUTH", - "GAR", - "GAZELLE", - "GECKO", - "GENET", - "GERBIL", - "GHARIAL", - "GIBBON", - "GIRAFFE", - "GOOSE", - "GOPHER", - "GORILLA", - "GOSHAWK", - "GRASSHOPPER", - "GREYHOUND", - "GRIZZLY", - "GROUPER", - "GROUSE", - "GRYPHON", - "GUANACO", - "GULL", - "GUPPY", - "HADDOCK", - "HAGFISH", - "HALIBUT", - "HAMSTER", - "HARAMBE", - "HARE", - "HARRIER", - "HAWK", - "HEDGEHOG", - "HERMITCRAB", - "HERON", - "HERRING", - "HIPPO", - "HORNBILL", - "HORNET", - "HORSE", - "HUNTSMAN", - "HUSKY", - "HYENA", - "IBEX", - "IBIS", - "IGUANA", - "IMPALA", - "INSECT", - "IRUKANDJI", - "ISOPOD", - "JACKAL", - "JAGUAR", - "JELLYFISH", - "JERBOA", - "KAKAPO", - "KANGAROO", - "KATYDID", - "KEA", - "KINGFISHER", - "KITTEN", - "KIWI", - "KOALA", - "KOMODO", - "KRAIT", - "LADYBUG", - "LAMPREY", - "LEMUR", - "LEOPARD", - "LIGHTFOOT", - "LION", - "LIONFISH", - "LIZARD", - "LLAMA", - "LOACH", - "LOBSTER", - "LOCUST", - "LORIKEET", - "LUNGFISH", - "LYNX", - "MACAW", - "MAGPIE", - "MALLARD", - "MAMBA", - "MAMMOTH", - "MANATEE", - "MANDRILL", - "MANTA", - "MANTIS", - "MARE", - "MARLIN", - "MARMOT", - "MARTEN", - "MASTIFF", - "MASTODON", - "MAVERICK", - "MAYFLY", - "MEERKAT", - "MILLIPEDE", - "MINK", - "MOA", - "MOCKINGBIRD", - "MOLE", - "MOLERAT", - "MOLLY", - "MONGOOSE", - "MONKEY", - "MONKFISH", - "MONSTER", - "MOOSE", - "MORAY", - "MOSQUITO", - "MOTH", - "MOUSE", - "MUDSKIPPER", - "MULE", - "MUSK", - "MYNA", - "NARWHAL", - "NAUTILUS", - "NEWT", - "NIGHTINGALE", - "NUMBAT", - "OCELOT", - "OCTOPUS", - "OKAPI", - "OLM", - "OPAH", - "OPOSSUM", - "ORCA", - "ORYX", - "OSPREY", - "OSTRICH", - "OTTER", - "OWL", - "OX", - "OYSTER", - "PADDLEFISH", - "PADEMELON", - "PANDA", - "PANGOLIN", - "PANTHER", - "PARAKEET", - "PARROT", - "PEACOCK", - "PELICAN", - "PENGUIN", - "PERCH", - "PEREGRINE", - "PETRAL", - "PHEASANT", - "PIG", - "PIGEON", - "PIGLET", - "PIKE", - "PIRANHA", - "PLATYPUS", - "POODLE", - "PORCUPINE", - "PORPOISE", - "POSSUM", - "POTOROO", - "PRONGHORN", - "PUFFERFISH", - "PUFFIN", - "PUG", - "PUMA", - "PYTHON", - "QUAGGA", - "QUAIL", - "QUOKKA", - "QUOLL", - "RABBIT", - "RACOON", - "RAGDOLL", - "RAT", - "RATTLESNAKE", - "RAVEN", - "REINDEER", - "RHINO", - "ROACH", - "ROBIN", - "SABERTOOTH", - "SAILFISH", - "SALAMANDER", - "SALMON", - "SANDFLY", - "SARDINE", - "SAWFISH", - "SCARAB", - "SCORPION", - "SEAHORSE", - "SEAL", - "SEALION", - "SERVAL", - "SHARK", - "SHEEP", - "SHOEBILL", - "SHRIKE", - "SHRIMP", - "SIDEWINDER", - "SILKWORM", - "SKATE", - "SKINK", - "SKUNK", - "SLOTH", - "SLUG", - "SNAIL", - "SNAKE", - "SNAPPER", - "SNOOK", - "SPARROW", - "SPIDER", - "SPRINGBOK", - "SQUID", - "SQUIRREL", - "STAGHORN", - "STARFISH", - "STINGRAY", - "STINKBUG", - "STOUT", - "STURGEON", - "SUGARGLIDER", - "SUNBEAR", - "SWALLOW", - "SWAN", - "SWIFT", - "SWORDFISH", - "TAIPAN", - "TAKAHE", - "TAMARIN", - "TANG", - "TAPIR", - "TARANTULA", - "TARPON", - "TARSIER", - "TAURUS", - "TERMITE", - "TERRIER", - "TETRA", - "THRUSH", - "THYLACINE", - "TIGER", - "TOAD", - "TORTOISE", - "TOUCAN", - "TREADFIN", - "TREVALLY", - "TRIGGERFISH", - "TROUT", - "TUATARA", - "TUNA", - "TURKEY", - "TURTLE", - "URCHIN", - "VIPER", - "VULTURE", - "WALLABY", - "WALLAROO", - "WALLEYE", - "WALRUS", - "WARTHOG", - "WASP", - "WATERBUCK", - "WEASEL", - "WEEVIL", - "WEKA", - "WHALE", - "WILDCAT", - "WILDEBEEST", - "WOLF", - "WOLFHOUND", - "WOLVERINE", - "WOMBAT", - "WOODCHUCK", - "WOODPECKER", - "WORM", - "WRASSE", - "WYVERN", - "YAK", - "ZEBRA", - "ZEBU", -) - - -class NameGenerator: - number = 0 - infantry_number = 0 - aircraft_number = 0 - convoy_number = 0 - cargo_ship_number = 0 - jtac_number = 0 - - animals: list[str] = list(ANIMALS) - existing_alphas: List[str] = [] - - @classmethod - def reset(cls) -> None: - cls.number = 0 - cls.infantry_number = 0 - cls.convoy_number = 0 - cls.cargo_ship_number = 0 - cls.jtac_number = 0 - cls.animals = list(ANIMALS) - cls.existing_alphas = [] - - @classmethod - def reset_numbers(cls) -> None: - cls.number = 0 - cls.infantry_number = 0 - cls.aircraft_number = 0 - cls.convoy_number = 0 - cls.cargo_ship_number = 0 - cls.jtac_number = 0 - - @classmethod - def next_aircraft_name(cls, country: Country, flight: Flight) -> str: - cls.aircraft_number += 1 - if flight.custom_name: - name_str = flight.custom_name - else: - name_str = "{} {}".format(flight.package.target.name, flight.flight_type) - return "{}|{}|{}|{}|".format( - name_str, country.id, cls.aircraft_number, flight.unit_type.variant_id - ) - - @classmethod - def next_unit_name(cls, country: Country, unit_type: UnitType[Any]) -> str: - cls.number += 1 - return "unit|{}|{}|{}|".format(country.id, cls.number, unit_type.variant_id) - - @classmethod - def next_infantry_name(cls, country: Country, unit_type: UnitType[Any]) -> str: - cls.infantry_number += 1 - return "infantry|{}|{}|{}|".format( - country.id, - cls.infantry_number, - unit_type.variant_id, - ) - - @classmethod - def next_awacs_name(cls, country: Country) -> str: - cls.number += 1 - return "awacs|{}|{}|0|".format(country.id, cls.number) - - @classmethod - def next_tanker_name(cls, country: Country, unit_type: AircraftType) -> str: - cls.number += 1 - return "tanker|{}|{}|0|{}".format(country.id, cls.number, unit_type.variant_id) - - @classmethod - def next_carrier_name(cls, country: Country) -> str: - cls.number += 1 - return "carrier|{}|{}|0|".format(country.id, cls.number) - - @classmethod - def next_convoy_name(cls) -> str: - cls.convoy_number += 1 - return f"Convoy {cls.convoy_number:03}" - - @classmethod - def next_cargo_ship_name(cls) -> str: - cls.cargo_ship_number += 1 - return f"Cargo Ship {cls.cargo_ship_number:03}" - - @classmethod - def next_jtac_name(cls) -> str: - name = ( - ALPHA_MILITARY[cls.jtac_number] - if cls.jtac_number < len(ALPHA_MILITARY) - else str(cls.jtac_number + 1) - ) - cls.jtac_number += 1 - return f"JTAC {name}" - - @classmethod - def random_objective_name(cls) -> str: - if cls.animals: - animal = random.choice(cls.animals) - cls.animals.remove(animal) - return animal - - for _ in range(10): - alpha = random.choice(ALPHA_MILITARY).upper() - number = random.randint(0, 100) - alpha_mil_name = f"{alpha} #{number:02}" - if alpha_mil_name not in cls.existing_alphas: - cls.existing_alphas.append(alpha_mil_name) - return alpha_mil_name - - # At this point, give up trying - something has gone wrong and we haven't been - # able to make a new name in 10 tries. We'll just make a longer name using the - # current unix epoch in nanoseconds. That should be unique... right? - last_chance_name = alpha_mil_name + str(time.time_ns()) - cls.existing_alphas.append(last_chance_name) - return last_chance_name - - -namegen = NameGenerator diff --git a/game/navmesh.py b/game/navmesh.py deleted file mode 100644 index e2b18f033..000000000 --- a/game/navmesh.py +++ /dev/null @@ -1,275 +0,0 @@ -from __future__ import annotations - -import heapq -import math -from collections import defaultdict -from dataclasses import dataclass, field -from typing import Dict, List, Optional, Set, Tuple, Union - -from dcs.mapping import Point -from shapely.geometry import ( - LineString, - MultiPolygon, - Point as ShapelyPoint, - Polygon, - box, -) -from shapely.ops import nearest_points, triangulate - -from game.theater import ConflictTheater -from game.threatzones import ThreatZones -from game.utils import nautical_miles - - -class NavMeshError(RuntimeError): - pass - - -class NavMeshPoly: - def __init__(self, ident: int, poly: Polygon, threatened: bool) -> None: - self.ident = ident - self.poly = poly - self.threatened = threatened - self.neighbors: Dict[NavMeshPoly, Union[LineString, ShapelyPoint]] = {} - - def __eq__(self, other: object) -> bool: - if not isinstance(other, NavMeshPoly): - return False - return self.ident == other.ident - - def __hash__(self) -> int: - return self.ident - - -@dataclass(frozen=True) -class NavPoint: - point: ShapelyPoint - poly: NavMeshPoly - - def world_point(self, theater: ConflictTheater) -> Point: - return Point(self.point.x, self.point.y, theater.terrain) - - def __hash__(self) -> int: - return hash(self.poly.ident) - - def __eq__(self, other: object) -> bool: - if id(self) == id(other): - return True - - if not isinstance(other, NavPoint): - return False - - # The tolerance value used here is the same that was used by the now deprecated - # almost_equals. - if not self.point.equals_exact(other.point, 0.5 * 10 ** (-6)): - return False - - return self.poly == other.poly - - def __str__(self) -> str: - return f"{self.point} in {self.poly.ident}" - - -@dataclass(frozen=True, order=True) -class FrontierNode: - cost: float - point: NavPoint = field(compare=False) - - -class NavFrontier: - def __init__(self) -> None: - self.nodes: List[FrontierNode] = [] - - def push(self, poly: NavPoint, cost: float) -> None: - heapq.heappush(self.nodes, FrontierNode(cost, poly)) - - def pop(self) -> Optional[NavPoint]: - try: - return heapq.heappop(self.nodes).point - except IndexError: - return None - - -class NavMesh: - def __init__(self, polys: List[NavMeshPoly], theater: ConflictTheater) -> None: - self.polys = polys - self.theater = theater - - def localize(self, point: Point) -> Optional[NavMeshPoly]: - # This is a naive implementation but it's O(n). Runs at about 10k - # lookups a second on a 5950X. Flights usually have 5-10 waypoints, so - # that's 1k-2k flights before we lose a full second to localization as a - # part of flight plan creation. - # - # Can improve the algorithm later if needed, but that seems unnecessary - # currently. - p = ShapelyPoint(point.x, point.y) - for navpoly in self.polys: - if navpoly.poly.intersects(p): - return navpoly - return None - - @staticmethod - def travel_cost(a: NavPoint, b: NavPoint) -> float: - modifier = 1.0 - if a.poly.threatened: - modifier = 3.0 - return a.point.distance(b.point) * modifier - - def travel_heuristic(self, a: NavPoint, b: NavPoint) -> float: - return self.travel_cost(a, b) - - def reconstruct_path( - self, - came_from: Dict[NavPoint, Optional[NavPoint]], - origin: NavPoint, - destination: NavPoint, - ) -> List[Point]: - current = destination - path: List[Point] = [] - while current != origin: - path.append(current.world_point(self.theater)) - previous = came_from[current] - if previous is None: - raise NavMeshError( - f"Could not reconstruct path to {destination} from {origin}" - ) - current = previous - path.append(origin.world_point(self.theater)) - path.reverse() - return path - - @staticmethod - def dcs_to_shapely_point(point: Point) -> ShapelyPoint: - return ShapelyPoint(point.x, point.y) - - def shortest_path(self, origin: Point, destination: Point) -> List[Point]: - origin_poly = self.localize(origin) - if origin_poly is None: - raise NavMeshError(f"Origin point {origin} is outside the navmesh") - destination_poly = self.localize(destination) - if destination_poly is None: - raise NavMeshError( - f"Destination point {destination} is outside the navmesh" - ) - - return self._shortest_path( - NavPoint(self.dcs_to_shapely_point(origin), origin_poly), - NavPoint(self.dcs_to_shapely_point(destination), destination_poly), - ) - - def _shortest_path(self, origin: NavPoint, destination: NavPoint) -> List[Point]: - # Adapted from - # https://www.redblobgames.com/pathfinding/a-star/implementation.py. - frontier = NavFrontier() - frontier.push(origin, 0.0) - came_from: Dict[NavPoint, Optional[NavPoint]] = {origin: None} - - best_known: Dict[NavPoint, float] = defaultdict(lambda: math.inf) - best_known[origin] = 0.0 - - while (current := frontier.pop()) is not None: - if current == destination: - break - - if current.poly == destination.poly: - # Made it to the correct nav poly. Add the leg from the border - # to the target. - cost = best_known[current] + self.travel_cost(current, destination) - if cost < best_known[destination]: - best_known[destination] = cost - estimated = cost - frontier.push(destination, estimated) - came_from[destination] = current - - for neighbor, boundary in current.poly.neighbors.items(): - previous = came_from[current] - if previous is not None and previous.poly == neighbor: - # Don't backtrack. - continue - if previous is None and current != origin: - raise RuntimeError - _, neighbor_point = nearest_points(current.point, boundary) - neighbor_nav = NavPoint(neighbor_point, neighbor) - cost = best_known[current] + self.travel_cost(current, neighbor_nav) - if cost < best_known[neighbor_nav]: - best_known[neighbor_nav] = cost - estimated = cost + self.travel_heuristic(neighbor_nav, destination) - frontier.push(neighbor_nav, estimated) - came_from[neighbor_nav] = current - - return self.reconstruct_path(came_from, origin, destination) - - @staticmethod - def map_bounds(theater: ConflictTheater) -> Polygon: - points = [] - for cp in theater.controlpoints: - points.append(ShapelyPoint(cp.position.x, cp.position.y)) - for tgo in cp.ground_objects: - points.append(ShapelyPoint(tgo.position.x, tgo.position.y)) - # Needs to be a large enough boundary beyond the known points so that - # threatened airbases at the map edges have room to retreat from the - # threat without running off the navmesh. - return box(*LineString(points).bounds).buffer( - nautical_miles(200).meters, resolution=1 - ) - - @staticmethod - def create_navpolys( - polys: List[Polygon], threat_zones: ThreatZones - ) -> List[NavMeshPoly]: - return [ - NavMeshPoly(i, p, threat_zones.threatened(p)) for i, p in enumerate(polys) - ] - - @staticmethod - def associate_neighbors(polys: List[NavMeshPoly]) -> None: - # Maps (rounded) points to polygons that have a vertex at that point. - # The points are rounded to the nearest int so we can use them as dict - # keys. This allows us to perform approximate neighbor lookups more - # efficiently than comparing each poly to every other poly by finding - # approximate neighbors before checking if the polys actually touch. - points_map: Dict[Tuple[int, int], Set[NavMeshPoly]] = defaultdict(set) - - for navpoly in polys: - # The coordinates of the polygon's boundary are a sequence of - # coordinates that define the polygon. The first point is repeated - # at the end, so skip the last vertex. - for x, y in navpoly.poly.boundary.coords[:-1]: - point = (int(x), int(y)) - neighbors = {} - for potential_neighbor in points_map[point]: - intersection = navpoly.poly.intersection(potential_neighbor.poly) - if not intersection.is_empty: - potential_neighbor.neighbors[navpoly] = intersection - neighbors[potential_neighbor] = intersection - navpoly.neighbors.update(neighbors) - points_map[point].add(navpoly) - - @classmethod - def from_threat_zones( - cls, threat_zones: ThreatZones, theater: ConflictTheater - ) -> NavMesh: - # Simplify the threat poly to reduce the number of nav zones. Increase - # the size of the zone and then simplify it with the buffer size as the - # error margin. This will create a simpler poly around the threat zone. - buffer = nautical_miles(10).meters - threat_poly = threat_zones.all.buffer(buffer).simplify(buffer) - - # Threat zones can be disconnected. Create a list of threat zones. - if isinstance(threat_poly, MultiPolygon): - polys = list(threat_poly.geoms) - else: - polys = [threat_poly] - - # Subtract the threat zones from the whole-map poly to build a navmesh - # for the *safe* areas. Navigation within threatened regions is always - # a straight line to the target or out of the threatened region. - bounds = cls.map_bounds(theater) - for poly in polys: - bounds = bounds.difference(poly) - - # Triangulate the safe-region to build the navmesh. - navpolys = cls.create_navpolys(triangulate(bounds), threat_zones) - cls.associate_neighbors(navpolys) - return NavMesh(navpolys, theater) diff --git a/game/orderedset.py b/game/orderedset.py deleted file mode 100644 index fcc288895..000000000 --- a/game/orderedset.py +++ /dev/null @@ -1,23 +0,0 @@ -from collections.abc import Iterable, Iterator -from typing import Generic, Optional, TypeVar - -ValueT = TypeVar("ValueT") - - -class OrderedSet(Generic[ValueT]): - def __init__(self, initial_data: Optional[Iterable[ValueT]] = None) -> None: - if initial_data is None: - initial_data = [] - self._data: dict[ValueT, None] = {v: None for v in initial_data} - - def __iter__(self) -> Iterator[ValueT]: - yield from self._data - - def __contains__(self, item: ValueT) -> bool: - return item in self._data - - def add(self, item: ValueT) -> None: - self._data[item] = None - - def clear(self) -> None: - self._data.clear() diff --git a/game/persistence/__init__.py b/game/persistence/__init__.py deleted file mode 100644 index d2e67cf9d..000000000 --- a/game/persistence/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .paths import base_path, mission_path_for, set_dcs_save_game_directory -from .savemanager import SaveManager diff --git a/game/persistence/paths.py b/game/persistence/paths.py deleted file mode 100644 index 6133e4579..000000000 --- a/game/persistence/paths.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -_dcs_saved_game_folder: Path | None = None - - -def set_dcs_save_game_directory(user_folder: Path) -> None: - global _dcs_saved_game_folder - _dcs_saved_game_folder = user_folder - if not save_dir().exists(): - save_dir().mkdir(parents=True) - - -def base_path() -> str: - global _dcs_saved_game_folder - assert _dcs_saved_game_folder is not None - return str(_dcs_saved_game_folder) - - -def liberation_user_dir() -> Path: - """The path to the Liberation user directory.""" - return Path(base_path()) / "Liberation" - - -def save_dir() -> Path: - return liberation_user_dir() / "Saves" - - -def mission_path_for(name: str) -> Path: - return Path(base_path()) / "Missions" / name - - -def waypoint_debug_directory() -> Path: - return liberation_user_dir() / "Debug/Waypoints" diff --git a/game/persistence/savegamebundle.py b/game/persistence/savegamebundle.py deleted file mode 100644 index 92af1883d..000000000 --- a/game/persistence/savegamebundle.py +++ /dev/null @@ -1,136 +0,0 @@ -from __future__ import annotations - -import logging -import pickle -import shutil -from pathlib import Path -from tempfile import NamedTemporaryFile -from typing import TYPE_CHECKING -from zipfile import ZIP_LZMA, ZipFile - -from game.profiling import logged_duration -from game.zipfileext import ZipFileExt - -if TYPE_CHECKING: - from game import Game - - -class SaveGameBundle: - """The bundle of saved game assets. - - A save game bundle includes the pickled game object (as well as some backups of - other game states, like the turn start and previous turn) and the state.json. - """ - - MANUAL_SAVE_NAME = "player.liberation" - LAST_TURN_SAVE_NAME = "last_turn.liberation" - START_OF_TURN_SAVE_NAME = "start_of_turn.liberation" - PRE_SIM_CHECKPOINT_SAVE_NAME = "pre_sim_checkpoint.liberation" - - def __init__(self, bundle_path: Path) -> None: - self.bundle_path = bundle_path - - def save_player(self, game: Game, copy_from: SaveGameBundle | None) -> None: - """Writes the save game manually created by the player. - - This save is the one created whenever the player presses save or save-as. - """ - with logged_duration("Saving game"): - self._update_bundle_member(game, self.MANUAL_SAVE_NAME, copy_from) - - def save_last_turn(self, game: Game) -> None: - """Writes the save for the state of the previous turn. - - This save is the state of the game before the state.json changes are applied. - This is mostly useful as a debugging tool for bugs that occur in the turn - transition, but can also be used by players to "rewind" to the previous turn. - """ - with logged_duration("Saving last turn"): - self._update_bundle_member(game, self.LAST_TURN_SAVE_NAME, copy_from=self) - - def save_start_of_turn(self, game: Game) -> None: - """Writes the save for the state at the start of the turn. - - This save is the state of the game immediately after the state.json is applied. - It can be used by players to "rewind" to the start of the turn. - """ - with logged_duration("Saving start of turn"): - self._update_bundle_member( - game, self.START_OF_TURN_SAVE_NAME, copy_from=self - ) - - def save_pre_sim_checkpoint(self, game: Game) -> None: - """Writes the save file for the state before beginning simulation. - - This save is the state of the game after the player presses "TAKE OFF", but - before the fast-forward simulation begins. It is not practical to rewind, but - players commonly will want to cancel and continue planning after pressing that - button, so we make a checkpoint that we can reload on abort. - """ - with logged_duration("Saving pre-sim checkpoint"): - self._update_bundle_member( - game, self.PRE_SIM_CHECKPOINT_SAVE_NAME, copy_from=self - ) - - def load_player(self) -> Game: - """Loads the save manually created by the player via save/save-as.""" - return self._load_from(self.MANUAL_SAVE_NAME) - - def load_start_of_turn(self) -> Game: - """Loads the save automatically created at the start of the turn.""" - return self._load_from(self.START_OF_TURN_SAVE_NAME) - - def load_last_turn(self) -> Game: - """Loads the save automatically created at the end of the last turn.""" - return self._load_from(self.LAST_TURN_SAVE_NAME) - - def load_pre_sim_checkpoint(self) -> Game: - """Loads the save automatically created before the simulation began.""" - return self._load_from(self.PRE_SIM_CHECKPOINT_SAVE_NAME) - - def _load_from(self, name: str) -> Game: - with ZipFile(self.bundle_path) as zip_bundle: - with zip_bundle.open(name, "r") as save: - game = pickle.load(save) - game.save_manager.set_loaded_from(self) - return game - - def _update_bundle_member( - self, game: Game, name: str, copy_from: SaveGameBundle | None - ) -> None: - # Perform all save work in a copy of the current save to avoid corrupting the - # save if there's an error while saving. - with NamedTemporaryFile( - "wb", suffix=".liberation.zip", delete=False - ) as temp_save_file: - temp_file_path = Path(temp_save_file.name) - - # We don't have all the state to create the temporary save from scratch (no last - # turn, start of turn, etc.), so copy the existing save to create the temp save. - # - # Python doesn't actually support overwriting or removing zipfile members, so we - # have to create a new zipfile and copy over only the files that we won't be - # writing. - if copy_from is not None and copy_from.bundle_path.exists(): - shutil.copy(copy_from.bundle_path, temp_file_path) - ZipFileExt.remove_member(temp_file_path, name, missing_ok=True) - - with ZipFile(temp_file_path, "a", compression=ZIP_LZMA) as zip_bundle: - with zip_bundle.open(name, "w") as entry: - pickle.dump(game, entry) - - try: - temp_file_path.replace(self.bundle_path) - except OSError: - # The file might be copyable but not movable if the temp and saved game - # directories are on different file systems. - # https://github.com/dcs-liberation/dcs_liberation/issues/2748 - shutil.copy(temp_file_path, self.bundle_path) - temp_file_path.unlink() - logging.warning( - "Save game %s was copyable from temporary location %s but not " - "moveable. The temp directory and save game directory might be on " - "different file systems. This makes saving the game slower.", - self.bundle_path, - temp_file_path, - ) diff --git a/game/persistence/savemanager.py b/game/persistence/savemanager.py deleted file mode 100644 index 3e787330d..000000000 --- a/game/persistence/savemanager.py +++ /dev/null @@ -1,105 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from contextlib import contextmanager -from pathlib import Path -from typing import TYPE_CHECKING - -from qt_ui import liberation_install -from .paths import save_dir -from .savegamebundle import SaveGameBundle - -if TYPE_CHECKING: - from game.game import Game - - -class SaveManager: - def __init__(self, game: Game) -> None: - self.game = game - self.player_save_location: Path | None = None - self.last_saved_bundle: SaveGameBundle | None = None - - @property - def autosave_path(self) -> Path: - # This is a property rather than a member because it's one less thing we need to - # update when loading a save that may have been copied from another machine. - return self.default_save_directory() / "autosave.liberation.zip" - - @property - def default_save_location(self) -> Path: - if self.player_save_location is not None: - return self.player_save_location - return self.autosave_path - - @property - def default_save_bundle(self) -> SaveGameBundle: - return SaveGameBundle(self.default_save_location) - - def save_player(self, override_destination: Path | None = None) -> None: - copy_from = self.last_saved_bundle - with self._save_bundle_context(override_destination) as bundle: - self.player_save_location = bundle.bundle_path - bundle.save_player(self.game, copy_from) - liberation_install.setup_last_save_file(str(bundle.bundle_path)) - liberation_install.save_config() - - def save_last_turn(self) -> None: - with self._save_bundle_context() as bundle: - bundle.save_last_turn(self.game) - - def save_start_of_turn(self) -> None: - with self._save_bundle_context() as bundle: - bundle.save_start_of_turn(self.game) - - def save_pre_sim_checkpoint(self) -> None: - with self._save_bundle_context() as bundle: - bundle.save_pre_sim_checkpoint(self.game) - - def set_loaded_from(self, bundle: SaveGameBundle) -> None: - """Reconfigures this save manager based on the loaded game. - - The SaveManager is persisted to Game, including details like the last saved path - and bundle details. This data is no longer valid if the save was moved manually - (such as from one machine to another), so it needs to be replaced with the load - location. - - This should only be called by SaveGameBundle after a game load. - """ - self.player_save_location = bundle.bundle_path - self.last_saved_bundle = bundle - - @contextmanager - def _save_bundle_context( - self, override_destination: Path | None = None - ) -> Iterator[SaveGameBundle]: - if override_destination is not None: - bundle = SaveGameBundle(override_destination) - else: - bundle = self.default_save_bundle - - previous_saved_bundle = self.last_saved_bundle - try: - self.last_saved_bundle = bundle - yield bundle - except Exception: - self.last_saved_bundle = previous_saved_bundle - raise - - def load_pre_sim_checkpoint(self) -> Game: - return self.default_save_bundle.load_pre_sim_checkpoint() - - @staticmethod - def load_last_turn(bundle_path: Path) -> Game: - return SaveGameBundle(bundle_path).load_last_turn() - - @staticmethod - def load_start_of_turn(bundle_path: Path) -> Game: - return SaveGameBundle(bundle_path).load_start_of_turn() - - @staticmethod - def load_player_save(bundle_path: Path) -> Game: - return SaveGameBundle(bundle_path).load_player() - - @staticmethod - def default_save_directory() -> Path: - return save_dir() diff --git a/game/plugins/__init__.py b/game/plugins/__init__.py deleted file mode 100644 index 2203739d3..000000000 --- a/game/plugins/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .luaplugin import LuaPlugin -from .manager import LuaPluginManager diff --git a/game/plugins/luaplugin.py b/game/plugins/luaplugin.py deleted file mode 100644 index d5587c00c..000000000 --- a/game/plugins/luaplugin.py +++ /dev/null @@ -1,223 +0,0 @@ -from __future__ import annotations - -import json -import logging -import textwrap -from dataclasses import dataclass -from pathlib import Path -from typing import List, Optional, TYPE_CHECKING - -if TYPE_CHECKING: - from game.missiongenerator.luagenerator import LuaGenerator - - -class LuaPluginWorkOrder: - """A script to be loaded at mision start. - - Typically, a work order is used for the main plugin script, and another for - configuration. The main script is added to scriptsWorkOrders and the configuration - to configurationWorkOrders. As far as I can tell, there's absolutely no difference - between those two lists and that could be merged. - - Other scripts can also be run by being added to either of these lists. - - A better name for this is probably just "LuaPluginScript", since that appears to be - all they are. - """ - - def __init__( - self, parent_mnemonic: str, filename: str, mnemonic: str, disable: bool - ) -> None: - self.parent_mnemonic = parent_mnemonic - self.filename = filename - self.mnemonic = mnemonic - self.disable = disable - - def work(self, lua_generator: LuaGenerator) -> None: - """Inject the script for this work order into the mission, or ignores it.""" - if self.disable: - lua_generator.bypass_plugin_script(self.mnemonic) - else: - lua_generator.inject_plugin_script( - self.parent_mnemonic, self.filename, self.mnemonic - ) - - -class PluginSettings: - """A common base for plugin configuration and per-plugin option configuration.""" - - def __init__(self, identifier: str, enabled_by_default: bool) -> None: - self.identifier = identifier - self.enabled = enabled_by_default - - def set_enabled(self, enabled: bool) -> None: - self.enabled = enabled - - -class LuaPluginOption(PluginSettings): - """A boolean option for the plugin.""" - - def __init__(self, identifier: str, name: str, enabled_by_default: bool) -> None: - super().__init__(identifier, enabled_by_default) - self.name = name - - -@dataclass(frozen=True) -class LuaPluginDefinition: - """Object mapping for plugin.json.""" - - identifier: str - name: str - present_in_ui: bool - enabled_by_default: bool - options: List[LuaPluginOption] - work_orders: List[LuaPluginWorkOrder] - config_work_orders: List[LuaPluginWorkOrder] - - @classmethod - def from_json(cls, name: str, path: Path) -> LuaPluginDefinition: - """Loads teh plugin definitions from the given plugin.json path.""" - data = json.loads(path.read_text()) - - options = [] - for option in data.get("specificOptions"): - option_id = option["mnemonic"] - options.append( - LuaPluginOption( - identifier=f"{name}.{option_id}", - name=option.get("nameInUI", name), - enabled_by_default=option.get("defaultValue"), - ) - ) - - work_orders = [] - for work_order in data.get("scriptsWorkOrders"): - work_orders.append( - LuaPluginWorkOrder( - name, - work_order.get("file"), - work_order["mnemonic"], - work_order.get("disable", False), - ) - ) - config_work_orders = [] - for work_order in data.get("configurationWorkOrders"): - config_work_orders.append( - LuaPluginWorkOrder( - name, - work_order.get("file"), - work_order["mnemonic"], - work_order.get("disable", False), - ) - ) - - return cls( - identifier=name, - name=data["nameInUI"], - present_in_ui=not data.get("skipUI", False), - enabled_by_default=data.get("defaultValue", False), - options=options, - work_orders=work_orders, - config_work_orders=config_work_orders, - ) - - -class LuaPlugin(PluginSettings): - """A Liberation lua plugin. - - A plugin is a mod that is able to inject Lua code into the Liberation mission start - up. Some of these are bundled (Skynet, mist, EWRS, etc), but users can add their own - as well. - - A plugin is defined by a plugin.json file in resources/plugins//plugin.json. - That file defines the name to be shown in the settings UI, whether it should be - enabled by default, the scripts to run, and (optionally) boolean options for - controlling plugin behavior. - - The plugin identifier is defined by the name of the directory containing it. - - Plugin options have their own set of default settings, UI names, and IDs. - """ - - def __init__(self, definition: LuaPluginDefinition) -> None: - self.definition = definition - super().__init__(self.definition.identifier, self.definition.enabled_by_default) - - @property - def name(self) -> str: - return self.definition.name - - @property - def show_in_ui(self) -> bool: - return self.definition.present_in_ui - - @property - def options(self) -> List[LuaPluginOption]: - return self.definition.options - - def is_option_enabled(self, identifier: str) -> bool: - for option in self.options: - if option.identifier == identifier: - return option.enabled - raise KeyError(f"Plugin {self.identifier} has no option {self.identifier}") - - @classmethod - def from_json(cls, name: str, path: Path) -> Optional[LuaPlugin]: - try: - definition = LuaPluginDefinition.from_json(name, path) - except KeyError: - logging.exception("Required plugin configuration value missing") - return None - - return cls(definition) - - def inject_scripts(self, lua_generator: LuaGenerator) -> None: - """Injects the plugin's scripts into the mission.""" - for work_order in self.definition.work_orders: - work_order.work(lua_generator) - - def inject_configuration(self, lua_generator: LuaGenerator) -> None: - """Injects the plugin's options and configuration scripts into the mission. - - It's not clear why the script portion of this needs to exist, and could probably - instead be the same as inject_scripts. - """ - # inject the plugin options - if self.options: - option_decls = [] - for option in self.options: - enabled = str(option.enabled).lower() - name = option.identifier - option_decls.append(f" dcsLiberation.plugins.{name} = {enabled}") - - joined_options = "\n".join(option_decls) - - lua = textwrap.dedent( - f"""\ - -- {self.identifier} plugin configuration. - - if dcsLiberation then - if not dcsLiberation.plugins then - dcsLiberation.plugins = {{}} - end - dcsLiberation.plugins.{self.identifier} = {{}} - {joined_options} - end - - """ - ) - - lua_generator.inject_lua_trigger( - lua, f"{self.identifier} plugin configuration" - ) - - for work_order in self.definition.config_work_orders: - work_order.work(lua_generator) - - def update_with(self, other: LuaPlugin) -> None: - self.enabled = other.enabled - for option in self.options: - try: - option.enabled = other.is_option_enabled(option.identifier) - except KeyError: - continue diff --git a/game/plugins/manager.py b/game/plugins/manager.py deleted file mode 100644 index 70b42d33b..000000000 --- a/game/plugins/manager.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import annotations - -import json -import logging -from collections.abc import Iterator -from pathlib import Path -from typing import Any - -import yaml - -from game.persistence.paths import liberation_user_dir -from .luaplugin import LuaPlugin - - -class LuaPluginManager: - """Manages available and loaded lua plugins.""" - - def __init__(self, plugins: dict[str, LuaPlugin]) -> None: - self._plugins: dict[str, LuaPlugin] = plugins - - @staticmethod - def load() -> LuaPluginManager: - plugins_path = Path("resources/plugins") - - path = plugins_path / "plugins.json" - if not path.exists(): - raise RuntimeError(f"{path} does not exist. Cannot continue.") - - logging.info(f"Reading plugins list from {path}") - - plugins = {} - data = json.loads(path.read_text()) - for name in data: - plugin_path = plugins_path / name / "plugin.json" - if not plugin_path.exists(): - raise RuntimeError( - f"Invalid plugin configuration: required plugin {name} " - f"does not exist at {plugin_path}" - ) - logging.info(f"Loading plugin {name} from {plugin_path}") - plugin = LuaPlugin.from_json(name, plugin_path) - if plugin is not None: - plugins[name] = plugin - return LuaPluginManager(plugins) - - def update_with(self, other: LuaPluginManager) -> None: - """Updates all setting values with those in the given plugin manager. - - When a game is loaded, LuaPluginManager.load() is called to load the latest set - of plugins and settings. This is called with the plugin manager that was saved - to the Game object to preserve any options that were set, and then the Game is - updated with this manager. - - This needs to happen because the set of available plugins (or their options) can - change between runs. - """ - for plugin in self.iter_plugins(): - try: - old_plugin = other.by_id(plugin.identifier) - except KeyError: - continue - plugin.update_with(old_plugin) - - def iter_plugins(self) -> Iterator[LuaPlugin]: - yield from self._plugins.values() - - def by_id(self, identifier: str) -> LuaPlugin: - return self._plugins[identifier] - - def is_plugin_enabled(self, plugin_id: str) -> bool: - try: - return self.by_id(plugin_id).enabled - except KeyError: - return False - - def is_option_enabled(self, plugin_id: str, option_id: str) -> bool: - try: - return self.by_id(plugin_id).is_option_enabled(option_id) - except KeyError: - return False - - def save_player_settings(self) -> None: - """Saves the player's global settings to the user directory.""" - settings: dict[str, dict[str, Any]] = {} - for plugin in self.iter_plugins(): - if not plugin.show_in_ui: - continue - - plugin_settings: dict[str, Any] = {"enabled": plugin.enabled} - if plugin.options: - plugin_settings["options"] = {} - settings[plugin.identifier] = plugin_settings - for option in plugin.options: - plugin_settings["options"][option.identifier] = option.enabled - - with self._player_settings_file.open("w", encoding="utf-8") as settings_file: - yaml.dump(settings, settings_file, sort_keys=False, explicit_start=True) - - def merge_player_settings(self) -> None: - """Updates with the player's global settings.""" - settings_path = self._player_settings_file - if not settings_path.exists(): - return - with settings_path.open(encoding="utf-8") as settings_file: - data = yaml.safe_load(settings_file) - - for plugin_id, plugin_data in data.items(): - try: - plugin = self.by_id(plugin_id) - except KeyError: - logging.warning( - "Unexpected plugin ID found in %s: %s. Ignoring.", - settings_path, - plugin_id, - ) - continue - - plugin.enabled = plugin_data["enabled"] - for option in plugin.options: - try: - option.enabled = plugin_data["options"][option.identifier] - except KeyError: - pass - - @property - def _player_settings_file(self) -> Path: - """Returns the path to the player's global settings file.""" - return liberation_user_dir() / "plugins.yaml" diff --git a/game/point_with_heading.py b/game/point_with_heading.py deleted file mode 100644 index c55569bf0..000000000 --- a/game/point_with_heading.py +++ /dev/null @@ -1,27 +0,0 @@ -from __future__ import annotations - -import math - -from dcs import Point -from dcs.terrain import Terrain - -from game.utils import Heading - - -class PointWithHeading(Point): - def __init__(self, x: float, y: float, heading: Heading, terrain: Terrain) -> None: - super().__init__(x, y, terrain) - self.heading: Heading = heading - - @staticmethod - def from_point(point: Point, heading: Heading) -> PointWithHeading: - return PointWithHeading(point.x, point.y, heading, point._terrain) - - def rotate(self, origin: Point, heading: Heading) -> None: - """Rotates the Point by a given angle clockwise around the origin""" - ox, oy = origin.x, origin.y - px, py = self.x, self.y - radians = heading.radians - - self.x = ox + math.cos(radians) * (px - ox) - math.sin(radians) * (py - oy) - self.y = oy + math.sin(radians) * (px - ox) + math.cos(radians) * (py - oy) diff --git a/game/polldebriefingfilethread.py b/game/polldebriefingfilethread.py deleted file mode 100644 index f637168a2..000000000 --- a/game/polldebriefingfilethread.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations - -import json -import logging -import os -import time -from pathlib import Path -from threading import Event, Thread -from typing import Callable, TYPE_CHECKING - -if TYPE_CHECKING: - from game.debriefing import Debriefing - from game.sim import MissionSimulation - - -class PollDebriefingFileThread(Thread): - """Thread class with a stop() method. The thread itself has to check - regularly for the stopped() condition.""" - - def __init__( - self, - callback: Callable[[Debriefing], None], - mission_sim: MissionSimulation, - ) -> None: - super().__init__() - self._stop_event = Event() - self.callback = callback - self.mission_sim = mission_sim - - def stop(self) -> None: - self._stop_event.set() - - def stopped(self) -> bool: - return self._stop_event.is_set() - - def run(self) -> None: - if os.path.isfile("state.json"): - last_modified = os.path.getmtime("state.json") - else: - last_modified = 0 - while not self.stopped(): - try: - if ( - os.path.isfile("state.json") - and os.path.getmtime("state.json") > last_modified - ): - self.callback( - self.mission_sim.debrief_current_state(Path("state.json")) - ) - break - except json.JSONDecodeError: - logging.exception( - "Failed to decode state.json. Probably attempted read while DCS " - "was still writing the file. Will retry in 5 seconds." - ) - time.sleep(5) diff --git a/game/positioned.py b/game/positioned.py deleted file mode 100644 index 09952351d..000000000 --- a/game/positioned.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Protocol - -from dcs import Point - - -class Positioned(Protocol): - @property - def position(self) -> Point: - raise NotImplementedError diff --git a/game/procurement.py b/game/procurement.py deleted file mode 100644 index cb39c545a..000000000 --- a/game/procurement.py +++ /dev/null @@ -1,318 +0,0 @@ -from __future__ import annotations - -import math -import random -from dataclasses import dataclass -from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple - -from game.config import RUNWAY_REPAIR_COST -from game.data.units import UnitClass -from game.dcs.groundunittype import GroundUnitType -from game.theater import ControlPoint, MissionTarget - -if TYPE_CHECKING: - from game import Game - from game.ato import FlightType - from game.factions.faction import Faction - from game.squadrons import Squadron - -FRONTLINE_RESERVES_FACTOR = 1.3 - - -@dataclass(frozen=True) -class AircraftProcurementRequest: - near: MissionTarget - task_capability: FlightType - number: int - - def __str__(self) -> str: - task = self.task_capability.value - target = self.near.name - return f"{self.number} ship {task} near {target}" - - -class ProcurementAi: - def __init__( - self, - game: Game, - for_player: bool, - faction: Faction, - manage_runways: bool, - manage_front_line: bool, - manage_aircraft: bool, - ) -> None: - self.game = game - self.is_player = for_player - self.air_wing = game.air_wing_for(for_player) - self.faction = faction - self.manage_runways = manage_runways - self.manage_front_line = manage_front_line - self.manage_aircraft = manage_aircraft - self.threat_zones = self.game.threat_zone_for(not self.is_player) - - def calculate_ground_unit_budget_share(self) -> float: - armor_investment = 0 - aircraft_investment = 0 - - # faction has no ground units - if ( - len(self.faction.artillery_units) == 0 - and len(self.faction.frontline_units) == 0 - ): - return 0 - - # faction has no planes - if len(self.faction.aircrafts) == 0: - return 1 - - for cp in self.owned_points: - cp_ground_units = cp.allocated_ground_units( - self.game.coalition_for(self.is_player).transfers - ) - armor_investment += cp_ground_units.total_value - cp_aircraft = cp.allocated_aircraft() - aircraft_investment += cp_aircraft.total_value - - total_investment = aircraft_investment + armor_investment - if total_investment == 0: - # Turn 0 or all units were destroyed. Either way, split 30/70. - return 0.3 - - # the more planes we have, the more ground units we want and vice versa - ground_unit_share = aircraft_investment / total_investment - if ground_unit_share > 1.0: - raise ValueError - - return ground_unit_share - - def spend_budget(self, budget: float) -> float: - if self.manage_runways: - budget = self.repair_runways(budget) - if self.manage_front_line: - armor_budget = budget * self.calculate_ground_unit_budget_share() - budget -= armor_budget - budget += self.reinforce_front_line(armor_budget) - - if self.manage_aircraft: - budget = self.purchase_aircraft(budget) - return budget - - def repair_runways(self, budget: float) -> float: - for control_point in self.owned_points: - if budget < RUNWAY_REPAIR_COST: - break - if control_point.runway_can_be_repaired: - control_point.begin_runway_repair() - budget -= RUNWAY_REPAIR_COST - if self.is_player: - self.game.message( - "OPFOR has begun repairing the runway at " f"{control_point}" - ) - else: - self.game.message( - "We have begun repairing the runway at " f"{control_point}" - ) - return budget - - def affordable_ground_unit_of_class( - self, budget: float, unit_class: UnitClass - ) -> Optional[GroundUnitType]: - faction_units = set(self.faction.frontline_units) | set( - self.faction.artillery_units - ) - of_class = {u for u in faction_units if u.unit_class is unit_class} - - # faction has no access to needed unit type, take a random unit - if not of_class: - of_class = faction_units - - affordable_units = [u for u in of_class if u.price <= budget] - if not affordable_units: - return None - return random.choice(affordable_units) - - def reinforce_front_line(self, budget: float) -> float: - if not self.faction.frontline_units and not self.faction.artillery_units: - return budget - - # TODO: Attempt to transfer from reserves. - - while budget > 0: - cp = self.ground_reinforcement_candidate() - if cp is None: - break - - most_needed_type = self.most_needed_unit_class(cp) - unit = self.affordable_ground_unit_of_class(budget, most_needed_type) - if unit is None: - # Can't afford any more units. - break - - budget -= unit.price - cp.ground_unit_orders.order({unit: 1}) - - return budget - - def most_needed_unit_class(self, cp: ControlPoint) -> UnitClass: - worst_balanced: Optional[UnitClass] = None - worst_fulfillment = math.inf - for unit_class in UnitClass: - if not self.faction.has_access_to_unit_class(unit_class): - continue - - current_ratio = self.cost_ratio_of_ground_unit(cp, unit_class) - desired_ratio = ( - self.faction.doctrine.ground_unit_procurement_ratios.for_unit_class( - unit_class - ) - ) - if not desired_ratio: - continue - if current_ratio >= desired_ratio: - continue - fulfillment = current_ratio / desired_ratio - if fulfillment < worst_fulfillment: - worst_fulfillment = fulfillment - worst_balanced = unit_class - if worst_balanced is None: - return UnitClass.TANK - return worst_balanced - - @staticmethod - def fulfill_aircraft_request( - squadrons: list[Squadron], quantity: int, budget: float - ) -> Tuple[float, bool]: - for squadron in squadrons: - price = squadron.aircraft.price * quantity - # Final check to make sure the number of aircraft won't exceed the number of available pilots - # after fulfilling this aircraft request. - if ( - squadron.pilot_limits_enabled - and squadron.expected_size_next_turn + quantity - > squadron.expected_pilots_next_turn - ): - continue - if price > budget: - continue - - squadron.pending_deliveries += quantity - budget -= price - return budget, True - return budget, False - - def purchase_aircraft(self, budget: float) -> float: - for request in self.game.coalition_for(self.is_player).procurement_requests: - squadrons = list(self.best_squadrons_for(request)) - if not squadrons: - # No airbases in range of this request. Skip it. - continue - budget, fulfilled = self.fulfill_aircraft_request( - squadrons, request.number, budget - ) - if not fulfilled: - # The request was not fulfilled because we could not afford any suitable - # aircraft. Rather than continuing, which could proceed to buy tons of - # cheap escorts that will never allow us to plan a strike package, stop - # buying so we can save the budget until a turn where we *can* afford to - # fill the package. - break - return budget - - @property - def owned_points(self) -> List[ControlPoint]: - if self.is_player: - return self.game.theater.player_points() - else: - return self.game.theater.enemy_points() - - def best_squadrons_for( - self, request: AircraftProcurementRequest - ) -> Iterator[Squadron]: - threatened = [] - for squadron in self.air_wing.best_squadrons_for( - request.near, request.task_capability, request.number, this_turn=False - ): - if not squadron.can_provide_pilots(request.number): - continue - if not squadron.has_aircraft_capacity_for(request.number): - continue - if squadron.location.unclaimed_parking() < request.number: - continue - if self.threat_zones.threatened(squadron.location.position): - threatened.append(squadron) - continue - yield squadron - yield from threatened - - def ground_reinforcement_candidate(self) -> Optional[ControlPoint]: - worst_supply = math.inf - understaffed: Optional[ControlPoint] = None - - # Prefer to buy front line units at active front lines that are not - # already overloaded. - for cp in self.owned_points: - if not cp.has_active_frontline: - continue - - if not cp.has_ground_unit_source(self.game): - # No source of ground units, so can't buy anything. - continue - - purchase_target = cp.frontline_unit_count_limit * FRONTLINE_RESERVES_FACTOR - allocated = cp.allocated_ground_units( - self.game.coalition_for(self.is_player).transfers - ) - if allocated.total >= purchase_target: - # Control point is already sufficiently defended. - continue - if allocated.total < worst_supply: - worst_supply = allocated.total - understaffed = cp - - if understaffed is not None: - return understaffed - - # Otherwise buy reserves, but don't exceed the amount defined in the settings. - # These units do not exist in the world until the CP becomes - # connected to an active front line, at which point all these units - # will suddenly appear at the gates of the newly captured CP. - # - # To avoid sudden overwhelming numbers of units we avoid buying - # many. - # - # Also, do not bother buying units at bases that will never connect - # to a front line. - for cp in self.owned_points: - if cp.is_global: - continue - if not cp.can_recruit_ground_units(self.game): - continue - - allocated = cp.allocated_ground_units( - self.game.coalition_for(self.is_player).transfers - ) - if allocated.total >= self.game.settings.reserves_procurement_target: - continue - - if allocated.total < worst_supply: - worst_supply = allocated.total - understaffed = cp - - return understaffed - - def cost_ratio_of_ground_unit( - self, control_point: ControlPoint, unit_class: UnitClass - ) -> float: - allocations = control_point.allocated_ground_units( - self.game.coalition_for(self.is_player).transfers - ) - class_cost = 0 - total_cost = 0 - for unit_type, count in allocations.all.items(): - cost = unit_type.price * count - total_cost += cost - if unit_type.unit_class is unit_class: - class_cost += cost - if not total_cost: - return 0 - return class_cost / total_cost diff --git a/game/profiling.py b/game/profiling.py deleted file mode 100644 index a0f3f169e..000000000 --- a/game/profiling.py +++ /dev/null @@ -1,90 +0,0 @@ -from __future__ import annotations - -import logging -import timeit -from collections import defaultdict -from contextlib import contextmanager -from dataclasses import dataclass -from datetime import timedelta -from types import TracebackType -from typing import Iterator, Optional, Type - - -@contextmanager -def logged_duration(event: str) -> Iterator[None]: - timer = Timer() - with timer: - yield - logging.debug("%s took %s", event, timer.duration) - - -@dataclass -class CountedEvent: - count: int = 0 - duration: timedelta = timedelta() - - def increment(self, duration: timedelta) -> None: - self.count += 1 - self.duration += duration - - @property - def average(self) -> timedelta: - return self.duration / self.count - - -class MultiEventTracer: - def __init__(self) -> None: - self.events: dict[str, CountedEvent] = defaultdict(CountedEvent) - - def __enter__(self) -> MultiEventTracer: - return self - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - for event, counter in self.events.items(): - logging.debug( - "%s %d times took %s (%s average)", - event, - counter.count, - counter.duration, - counter.average, - ) - - @contextmanager - def trace(self, event: str) -> Iterator[None]: - timer = Timer() - with timer: - yield - self.events[event].increment(timer.duration) - - -class Timer: - def __init__(self) -> None: - self._start_time: float | None = None - self._end_time: float | None = None - self._duration: timedelta | None = None - - @property - def duration(self) -> timedelta: - if self._duration is None: - raise RuntimeError( - "Cannot query the duration of the timer before it has elapsed" - ) - return self._duration - - def __enter__(self) -> None: - self._start_time = timeit.default_timer() - - def __exit__( - self, - exc_type: Optional[Type[BaseException]], - exc_val: Optional[BaseException], - exc_tb: Optional[TracebackType], - ) -> None: - assert self._start_time is not None - self._end_time = timeit.default_timer() - self._duration = timedelta(seconds=self._end_time - self._start_time) diff --git a/game/provider.py b/game/provider.py deleted file mode 100644 index a2cc3cf00..000000000 --- a/game/provider.py +++ /dev/null @@ -1,4 +0,0 @@ -from typing import TypeAlias, TypeVar, Callable - -T = TypeVar("T") -Provider: TypeAlias = Callable[[], T] diff --git a/game/purchaseadapter.py b/game/purchaseadapter.py deleted file mode 100644 index 06aa712c9..000000000 --- a/game/purchaseadapter.py +++ /dev/null @@ -1,190 +0,0 @@ -from abc import abstractmethod -from typing import TypeVar, Generic, Any - -from game import Game -from game.coalition import Coalition -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.dcs.unittype import UnitType -from game.squadrons import Squadron -from game.theater import ControlPoint - -ItemType = TypeVar("ItemType") - - -class TransactionError(RuntimeError): - def __init__(self, message: str) -> None: - super().__init__(message) - - -class PurchaseAdapter(Generic[ItemType]): - def __init__(self, coalition: Coalition) -> None: - self.coalition = coalition - - def buy(self, item: ItemType, quantity: int) -> None: - for _ in range(quantity): - if self.has_pending_sales(item): - self.do_cancel_sale(item) - elif self.can_buy(item): - self.do_purchase(item) - else: - raise TransactionError(f"Cannot buy more {item}") - self.coalition.adjust_budget(-self.price_of(item)) - - def sell(self, item: ItemType, quantity: int) -> None: - for _ in range(quantity): - if self.has_pending_orders(item): - self.do_cancel_purchase(item) - elif self.can_sell(item): - self.do_sale(item) - else: - raise TransactionError(f"Cannot sell more {item}") - self.coalition.adjust_budget(self.price_of(item)) - - def has_pending_orders(self, item: ItemType) -> bool: - return self.pending_delivery_quantity(item) > 0 - - def has_pending_sales(self, item: ItemType) -> bool: - return self.pending_delivery_quantity(item) < 0 - - @abstractmethod - def current_quantity_of(self, item: ItemType) -> int: - ... - - @abstractmethod - def pending_delivery_quantity(self, item: ItemType) -> int: - ... - - def expected_quantity_next_turn(self, item: ItemType) -> int: - return self.current_quantity_of(item) + self.pending_delivery_quantity(item) - - def can_buy(self, item: ItemType) -> bool: - return self.coalition.budget >= self.price_of(item) - - def can_sell_or_cancel(self, item: ItemType) -> bool: - return self.can_sell(item) or self.has_pending_orders(item) - - @abstractmethod - def can_sell(self, item: ItemType) -> bool: - ... - - @abstractmethod - def do_purchase(self, item: ItemType) -> None: - ... - - @abstractmethod - def do_cancel_purchase(self, item: ItemType) -> None: - ... - - @abstractmethod - def do_sale(self, item: ItemType) -> None: - ... - - @abstractmethod - def do_cancel_sale(self, item: ItemType) -> None: - ... - - @abstractmethod - def price_of(self, item: ItemType) -> int: - ... - - @abstractmethod - def name_of(self, item: ItemType, multiline: bool = False) -> str: - ... - - @abstractmethod - def unit_type_of(self, item: ItemType) -> UnitType[Any]: - ... - - -class AircraftPurchaseAdapter(PurchaseAdapter[Squadron]): - def __init__(self, control_point: ControlPoint) -> None: - super().__init__(control_point.coalition) - self.control_point = control_point - - def pending_delivery_quantity(self, item: Squadron) -> int: - return item.pending_deliveries - - def current_quantity_of(self, item: Squadron) -> int: - return item.owned_aircraft - - def can_buy(self, item: Squadron) -> bool: - return ( - super().can_buy(item) - and self.control_point.unclaimed_parking() > 0 - and item.has_aircraft_capacity_for(1) - ) - - def can_sell(self, item: Squadron) -> bool: - return item.untasked_aircraft > 0 - - def do_purchase(self, item: Squadron) -> None: - item.pending_deliveries += 1 - - def do_cancel_purchase(self, item: Squadron) -> None: - item.pending_deliveries -= 1 - - def do_sale(self, item: Squadron) -> None: - item.untasked_aircraft -= 1 - item.pending_deliveries -= 1 - - def do_cancel_sale(self, item: Squadron) -> None: - item.untasked_aircraft += 1 - item.pending_deliveries += 1 - - def price_of(self, item: Squadron) -> int: - return item.aircraft.price - - def name_of(self, item: Squadron, multiline: bool = False) -> str: - if multiline: - separator = "
" - else: - separator = " " - return separator.join([item.aircraft.display_name, str(item)]) - - def unit_type_of(self, item: Squadron) -> AircraftType: - return item.aircraft - - -class GroundUnitPurchaseAdapter(PurchaseAdapter[GroundUnitType]): - def __init__( - self, control_point: ControlPoint, coalition: Coalition, game: Game - ) -> None: - super().__init__(coalition) - self.control_point = control_point - self.game = game - - def pending_delivery_quantity(self, item: GroundUnitType) -> int: - return self.control_point.ground_unit_orders.pending_orders(item) - - def current_quantity_of(self, item: GroundUnitType) -> int: - return self.control_point.base.total_units_of_type(item) - - def can_buy(self, item: GroundUnitType) -> bool: - return super().can_buy(item) and self.control_point.has_ground_unit_source( - self.game - ) - - def can_sell(self, item: GroundUnitType) -> bool: - return False - - def do_purchase(self, item: GroundUnitType) -> None: - self.control_point.ground_unit_orders.order({item: 1}) - - def do_cancel_purchase(self, item: GroundUnitType) -> None: - self.control_point.ground_unit_orders.sell({item: 1}) - - def do_sale(self, item: GroundUnitType) -> None: - raise TransactionError("Sale of ground units not allowed") - - def do_cancel_sale(self, item: GroundUnitType) -> None: - raise TransactionError("Sale of ground units not allowed") - - def price_of(self, item: GroundUnitType) -> int: - return item.price - - def name_of(self, item: GroundUnitType, multiline: bool = False) -> str: - return f"{item}" - - def unit_type_of(self, item: GroundUnitType) -> GroundUnitType: - return item diff --git a/game/radio/__init__.py b/game/radio/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/radio/channels.py b/game/radio/channels.py deleted file mode 100644 index e859a5a8c..000000000 --- a/game/radio/channels.py +++ /dev/null @@ -1,391 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any, Optional, TYPE_CHECKING - -if TYPE_CHECKING: - from game.missiongenerator.aircraft.flightdata import FlightData - from game.missiongenerator.missiondata import MissionData - - -class RadioChannelAllocator: - """Base class for radio channel allocators.""" - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - """Assigns mission frequencies to preset channels for the flight.""" - raise NotImplementedError - - @classmethod - def from_cfg(cls, cfg: dict[str, Any]) -> RadioChannelAllocator: - return cls() - - @classmethod - def name(cls) -> str: - raise NotImplementedError - - -@dataclass(frozen=True) -class CommonRadioChannelAllocator(RadioChannelAllocator): - """Radio channel allocator suitable for most aircraft. - - Most of the aircraft with preset channels available have one or more radios - with 20 or more channels available (typically per-radio, but this is not the - case for the JF-17). - """ - - #: Index of the radio used for intra-flight communications. Matches the - #: index of the panel_radio field of the pydcs.dcs.planes object. - inter_flight_radio_index: Optional[int] - - #: Index of the radio used for intra-flight communications. Matches the - #: index of the panel_radio field of the pydcs.dcs.planes object. - intra_flight_radio_index: Optional[int] - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - if self.intra_flight_radio_index is not None: - flight.assign_channel( - self.intra_flight_radio_index, 1, flight.intra_flight_channel - ) - - if self.inter_flight_radio_index is None: - return - - # For cases where the inter-flight and intra-flight radios share presets - # (the JF-17 only has one set of channels, even though it can use two - # channels simultaneously), start assigning inter-flight channels at 2. - radio_id = self.inter_flight_radio_index - if self.intra_flight_radio_index == radio_id: - first_channel = 2 - else: - first_channel = 1 - - last_channel = flight.num_radio_channels(radio_id) - channel_alloc = iter(range(first_channel, last_channel + 1)) - - if flight.departure.atc is not None: - flight.assign_channel(radio_id, next(channel_alloc), flight.departure.atc) - - # TODO: If there ever are multiple AWACS, limit to mission relevant. - for awacs in mission_data.awacs: - flight.assign_channel(radio_id, next(channel_alloc), awacs.freq) - - for jtac in mission_data.jtacs: - flight.assign_channel(radio_id, next(channel_alloc), jtac.freq) - - if flight.arrival != flight.departure and flight.arrival.atc is not None: - flight.assign_channel(radio_id, next(channel_alloc), flight.arrival.atc) - - try: - # TODO: Skip incompatible tankers. - for tanker in mission_data.tankers: - flight.assign_channel(radio_id, next(channel_alloc), tanker.freq) - - if flight.divert is not None and flight.divert.atc is not None: - flight.assign_channel(radio_id, next(channel_alloc), flight.divert.atc) - except StopIteration: - # Any remaining channels are nice-to-haves, but not necessary for - # the few aircraft with a small number of channels available. - pass - - @classmethod - def from_cfg(cls, cfg: dict[str, Any]) -> CommonRadioChannelAllocator: - return CommonRadioChannelAllocator( - inter_flight_radio_index=cfg["inter_flight_radio_index"], - intra_flight_radio_index=cfg["intra_flight_radio_index"], - ) - - @classmethod - def name(cls) -> str: - return "common" - - -@dataclass(frozen=True) -class NoOpChannelAllocator(RadioChannelAllocator): - """Channel allocator for aircraft that don't support preset channels.""" - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - pass - - @classmethod - def name(cls) -> str: - return "noop" - - -@dataclass(frozen=True) -class FarmerRadioChannelAllocator(RadioChannelAllocator): - """Preset channel allocator for the MiG-19P.""" - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - # The Farmer only has 6 preset channels. It also only has a VHF radio, - # and currently our ATC data and AWACS are only in the UHF band. - radio_id = 1 - flight.assign_channel(radio_id, 1, flight.intra_flight_channel) - # TODO: Assign 4-6 to VHF frequencies of departure, arrival, and divert. - # TODO: Assign 2 and 3 to AWACS if it is VHF. - - @classmethod - def name(cls) -> str: - return "farmer" - - -@dataclass(frozen=True) -class ViggenRadioChannelAllocator(RadioChannelAllocator): - """Preset channel allocator for the AJS37.""" - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - # The Viggen's preset channels are handled differently from other - # aircraft. Since 2.7.9 the group channels will not be generated automatically - # anymore. So we have to set AWACS and JTAC manually. There are also seven - # special channels we can modify. We'll set the first channel of the main radio - # to the intra-flight channel, and the first three emergency channels to each - # of the flight plan's airfields. The fourth emergency channel is always - # the guard channel. - radio_id = 1 - - # Possible Group Channels (100-139) - channel_alloc = iter(range(1, 40)) - - # Intra-Flight channel on Special 1 and Group 100 (required by module) - flight.assign_channel(radio_id, 41, flight.intra_flight_channel) # Special 1 - flight.assign_channel( - radio_id, next(channel_alloc), flight.intra_flight_channel - ) - - for awacs in mission_data.awacs: - flight.assign_channel(radio_id, next(channel_alloc), awacs.freq) - - for jtac in mission_data.jtacs: - flight.assign_channel(radio_id, next(channel_alloc), jtac.freq) - - if flight.departure.atc is not None: - flight.assign_channel(radio_id, 44, flight.departure.atc) # FR24 E - if flight.arrival.atc is not None: - flight.assign_channel(radio_id, 45, flight.arrival.atc) # FR24 F - if flight.divert is not None and flight.divert.atc is not None: - flight.assign_channel(radio_id, 46, flight.divert.atc) # FR24 G - - @classmethod - def name(cls) -> str: - return "viggen" - - -@dataclass(frozen=True) -class SCR522RadioChannelAllocator(RadioChannelAllocator): - """Preset channel allocator for the SCR522 WW2 radios. (4 channels)""" - - def assign_channels_for_flight( - self, flight: FlightData, mission_data: MissionData - ) -> None: - radio_id = 1 - flight.assign_channel(radio_id, 1, flight.intra_flight_channel) - if flight.departure.atc is not None: - flight.assign_channel(radio_id, 2, flight.departure.atc) - if flight.arrival.atc is not None: - flight.assign_channel(radio_id, 3, flight.arrival.atc) - - # TODO : Some GCI on Channel 4 ? - - @classmethod - def name(cls) -> str: - return "SCR-522" - - -class ChannelNamer: - """Base class allowing channel name customization per-aircraft. - - Most aircraft will want to customize this behavior, but the default is - reasonable for any aircraft with numbered radios. - """ - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - """Returns the name of the channel for the given radio and channel.""" - return f"COMM{radio_id} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "default" - - -class SingleRadioChannelNamer(ChannelNamer): - """Channel namer for the aircraft with only a single radio. - - Aircraft like the MiG-19P and the MiG-21bis only have a single radio, so - it's not necessary for us to name the radio when naming the channel. - """ - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - return f"Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "single" - - -class HueyChannelNamer(ChannelNamer): - """Channel namer for the UH-1H.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - return f"COM3 Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "huey" - - -class MirageChannelNamer(ChannelNamer): - """Channel namer for the M-2000.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - radio_name = ["V/UHF", "UHF"][radio_id - 1] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "mirage" - - -class MirageF1CEChannelNamer(ChannelNamer): - """Channel namer for the Mirage-F1CE.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - radio_name = ["V/UHF", "UHF"][radio_id - 1] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "mirage-f1CE" - - -class ApacheChannelNamer(ChannelNamer): - """Channel namer for the AH-64D Apache""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - # From the manual: Radio identifier (“VHF” for ARC-186, “UHF” for ARC-164, - # “FM1” for first ARC-201D, “FM2” for second ARC-201D, or “HF” for ARC-220). - radio_name = [ - "VHF", # ARC-186 - "UHF", # ARC-164 - "FM1", # first ARC-201D - "FM2", # second ARC-201D - "HF", # ARC-220 - ][radio_id - 1] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "apache" - - -class TomcatChannelNamer(ChannelNamer): - """Channel namer for the F-14.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - radio_name = ["UHF", "VHF/UHF"][radio_id - 1] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "tomcat" - - -class ViggenChannelNamer(ChannelNamer): - """Channel namer for the AJS37.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - special_channels = [ - "FR 22 Special 1", - "FR 22 Special 2", - "FR 22 Special 3", - "FR 24 E", - "FR 24 F", - "FR 24 G", - "FR 24 H", - ] - if channel_id >= 41: # Special channels are 41-47 - return special_channels[channel_id - 41] - return f"FR 22 Group {99 + channel_id}" - - @classmethod - def name(cls) -> str: - return "viggen" - - -class ViperChannelNamer(ChannelNamer): - """Channel namer for the F-16.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - return f"COM{radio_id} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "viper" - - -class SCR522ChannelNamer(ChannelNamer): - """ - Channel namer for P-51 & P-47D - """ - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - if channel_id > 3: - return "?" - else: - return f"Button " + "ABCD"[channel_id - 1] - - @classmethod - def name(cls) -> str: - return "SCR-522" - - -class LegacyWarthogChannelNamer(ChannelNamer): - """Channel namer for the legacy A-10C.""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - radio_name = { - 1: "VHF AM", - 2: "UHF", - 3: "VHF FM", - }[radio_id] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "a10c-legacy" - - -class WarthogChannelNamer(ChannelNamer): - """Channel namer for the legacy A-10C II""" - - @staticmethod - def channel_name(radio_id: int, channel_id: int) -> str: - radio_name = { - 1: "COM 1", - 2: "UHF", - 3: "VHF FM", - }[radio_id] - return f"{radio_name} Ch {channel_id}" - - @classmethod - def name(cls) -> str: - return "a10c-ii" diff --git a/game/radio/radios.py b/game/radio/radios.py deleted file mode 100644 index 2d7b28a1e..000000000 --- a/game/radio/radios.py +++ /dev/null @@ -1,407 +0,0 @@ -"""Radio frequency types and allocators.""" -from __future__ import annotations - -import itertools -import logging -import re -from dataclasses import dataclass -from typing import Dict, FrozenSet, Iterator, List, Set, Tuple - -from dcs.task import Modulation - - -@dataclass(frozen=True) -class RadioFrequency: - """A radio frequency and the modulation used""" - - #: The frequency in kilohertz. - hertz: int - - #: The frequency modulation (AM or FM) - # Pydcs defaults currently to modultion=0 which is equal to AM - # Modulation is currently only used to tell the User the Modulation via the - # kneeboard. We do not force any modulation from pydcs. We just set the - # frequency with the set_frequency function which does not allow to set the - # modulation yet. It defaults to modulation=0 which is equal to forcing AM - modulation: Modulation = Modulation.AM - - def __str__(self) -> str: - if self.hertz >= 1000000: - return self.format("MHz", 1000000) - return self.format("kHz", 1000) - - def format(self, units: str, divisor: int) -> str: - converted = self.hertz / divisor - if converted.is_integer(): - return f"{int(converted)} {units} {self.modulation.name}" - return f"{converted:0.3f} {units} {self.modulation.name}" - - @property - def mhz(self) -> float: - """Returns the frequency in megahertz. - - Returns: - The frequency in megahertz. - """ - return self.hertz / 1000000 - - @classmethod - def parse(cls, text: str, modulation: Modulation = Modulation.AM) -> RadioFrequency: - match = re.match(r"""^(\d+)(?:\.(\d{1,3}))? (MHz|kHz)$""", text) - if match is None: - raise ValueError(f"Could not parse radio frequency from {text}") - - whole = int(match.group(1)) - partial_str = match.group(2) - units = match.group(3) - - partial = 0 - if partial_str is not None: - partial = int(partial_str) - if len(partial_str) == 1: - partial *= 100 - elif len(partial_str) == 2: - partial *= 10 - - if units == "MHz": - return MHz(whole, partial, modulation) - if units == "kHz": - return kHz(whole, partial, modulation) - raise ValueError(f"Unexpected units in radio frequency: {units}") - - -def MHz( - num: int, khz: int = 0, modulation: Modulation = Modulation.AM -) -> RadioFrequency: - return RadioFrequency(num * 1000000 + khz * 1000, modulation) - - -def kHz( - num: int, hz: int = 0, modulation: Modulation = Modulation.AM -) -> RadioFrequency: - return RadioFrequency(num * 1000 + hz, modulation) - - -@dataclass(frozen=True) -class RadioRange: - """Defines the minimum (inclusive) and maximum (exclusive) range of the radio.""" - - #: The minimum (inclusive) frequency tunable by this radio. - minimum: RadioFrequency - - #: The maximum (exclusive) frequency tunable by this radio. - maximum: RadioFrequency - - #: The spacing between adjacent frequencies. - step: RadioFrequency - - #: Modulation, AM or FM. Defaulting to AM as it is more used for comms - # Overrides the modulation setting of the min and max frequency for the whole range - modulation: Modulation = Modulation.AM - - #: Specific frequencies to exclude. (e.g. Guard channels) - excludes: FrozenSet[RadioFrequency] = frozenset() - - def range(self) -> Iterator[RadioFrequency]: - """Returns an iterator over the usable frequencies of this radio.""" - return ( - RadioFrequency(x, self.modulation) - for x in range(self.minimum.hertz, self.maximum.hertz, self.step.hertz) - if RadioFrequency(x, self.modulation) not in self.excludes - ) - - @property - def last_channel(self) -> RadioFrequency: - return next( - RadioFrequency(x, self.modulation) - for x in reversed( - range(self.minimum.hertz, self.maximum.hertz, self.step.hertz) - ) - if RadioFrequency(x, self.modulation) not in self.excludes - ) - - -@dataclass(frozen=True) -class Radio: - """A radio. - - Defines ranges of usable frequencies of the radio. - """ - - #: The name of the radio. - name: str - - #: List of usable frequency range of this radio. - ranges: Tuple[RadioRange, ...] - - def __str__(self) -> str: - return self.name - - def range(self) -> Iterator[RadioFrequency]: - """Returns an iterator over the usable frequencies of this radio.""" - return itertools.chain.from_iterable(rng.range() for rng in self.ranges) - - @property - def last_channel(self) -> RadioFrequency: - return self.ranges[-1].last_channel - - -class ChannelInUseError(RuntimeError): - """Raised when attempting to reserve an in-use frequency.""" - - def __init__(self, frequency: RadioFrequency) -> None: - super().__init__(f"{frequency} is already in use") - - -# TODO: Figure out appropriate steps for each radio. These are just guesses. -#: List of all known radios used by aircraft in the game. -RADIOS: List[Radio] = [ - Radio("AN/ARC-164", (RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM),)), - Radio("AN/ARC-186(V) AM", (RadioRange(MHz(116), MHz(152), MHz(1), Modulation.AM),)), - Radio("AN/ARC-186(V) FM", (RadioRange(MHz(30), MHz(76), MHz(1), Modulation.FM),)), - Radio( - "AN/ARC-210", - ( - RadioRange( - MHz(225), - MHz(400), - MHz(1), - Modulation.AM, - frozenset((MHz(243),)), - ), - RadioRange(MHz(136), MHz(155), MHz(1), Modulation.AM), - RadioRange(MHz(156), MHz(174), MHz(1), Modulation.FM), - RadioRange(MHz(118), MHz(136), MHz(1), Modulation.AM), - RadioRange(MHz(30), MHz(88), MHz(1), Modulation.FM), - # The AN/ARC-210 can also use 225-400 and 136-155 with FM Modulation - RadioRange( - MHz(225), - MHz(400), - MHz(1), - Modulation.FM, - frozenset((MHz(243),)), - ), - RadioRange(MHz(136), MHz(155), MHz(1), Modulation.FM), - ), - ), - Radio("AN/ARC-222", (RadioRange(MHz(116), MHz(152), MHz(1), Modulation.AM),)), - Radio("SCR-522", (RadioRange(MHz(100), MHz(156), MHz(1), Modulation.AM),)), - Radio("A.R.I. 1063", (RadioRange(MHz(100), MHz(156), MHz(1), Modulation.AM),)), - Radio("BC-1206", (RadioRange(kHz(200), kHz(400), kHz(10), Modulation.AM),)), - Radio( - "TRT ERA 7000 V/UHF", - ( - RadioRange(MHz(118), MHz(150), MHz(1), Modulation.AM), - RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM), - ), - ), - Radio("TRT ERA 7200 UHF", (RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM),)), - # Tomcat radios - # # https://www.heatblur.se/F-14Manual/general.html#an-arc-159-uhf-1-radio - Radio("AN/ARC-159", (RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM),)), - # https://www.heatblur.se/F-14Manual/general.html#an-arc-182-v-uhf-2-radio - Radio( - "AN/ARC-182", - ( - RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM), - RadioRange(MHz(108), MHz(174), MHz(1), Modulation.AM), - # The Range from 30-88MHz should be FM but its modeled as AM in dcs - RadioRange(MHz(30), MHz(88), MHz(1), Modulation.AM), - ), - ), - Radio( - "FR 22", - ( - RadioRange(MHz(225), MHz(400), kHz(50), Modulation.AM), - RadioRange(MHz(103), MHz(156), kHz(25), Modulation.AM), - ), - ), - # P-51 / P-47 Radio - # 4 preset channels (A/B/C/D) - Radio("SCR522", (RadioRange(MHz(100), MHz(156), kHz(25), Modulation.AM),)), - # JF-17 Radios should use AM - Radio("R&S M3AR VHF", (RadioRange(MHz(120), MHz(174), MHz(1), Modulation.AM),)), - Radio("R&S M3AR UHF", (RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM),)), - # MiG-15bis - Radio("RSI-6K HF", (RadioRange(MHz(3, 750), MHz(5), kHz(25), Modulation.AM),)), - # MiG-19P - Radio("RSIU-4V", (RadioRange(MHz(100), MHz(150), MHz(1), Modulation.AM),)), - # MiG-21bis - Radio("RSIU-5V", (RadioRange(MHz(118), MHz(140), MHz(1), Modulation.AM),)), - # Ka-50 - # Note: Also capable of 100MHz-150MHz, but we can't model gaps. - Radio("R-800L1", (RadioRange(MHz(220), MHz(400), kHz(25), Modulation.AM),)), - Radio("R-828", (RadioRange(MHz(20), MHz(60), kHz(25), Modulation.FM),)), - # UH-1H - Radio("AN/ARC-51BX", (RadioRange(MHz(225), MHz(400), kHz(50), Modulation.AM),)), - Radio("AN/ARC-131", (RadioRange(MHz(30), MHz(76), kHz(50), Modulation.FM),)), - Radio("AN/ARC-134", (RadioRange(MHz(116), MHz(150), kHz(25), Modulation.AM),)), - # JAS39 - Radio("R&S Series 6000", (RadioRange(MHz(100), MHz(156), kHz(25), Modulation.AM),)), - # Mirage F1 - Radio( - "V/UHF TRAP 136", - ( - RadioRange(MHz(118), MHz(144), kHz(25), Modulation.AM), - RadioRange(MHz(225), MHz(400), kHz(25), Modulation.AM), - ), - ), - Radio("UHF TRAP 137B", (RadioRange(MHz(225), MHz(400), kHz(25), Modulation.AM),)), - Radio( - "AN/ARC-150(V) 2", - ( - RadioRange( - MHz(225), - MHz(400), - MHz(1), - Modulation.AM, - frozenset((MHz(243),)), - ), - ), - ), - Radio( - "SRT-651/N", - ( - RadioRange( - MHz(30), - MHz(88), - MHz(1), - Modulation.FM, - frozenset((MHz(40, 500),)), - ), - RadioRange( - MHz(108), - MHz(156), - MHz(1), - Modulation.AM, - frozenset((MHz(121, 500),)), - ), - RadioRange( - MHz(156), - MHz(174), - MHz(1), - Modulation.FM, - frozenset((MHz(156, 800),)), - ), - RadioRange( - MHz(225), - MHz(400), - MHz(1), - Modulation.AM, # Actually AM/FM, but we can't represent that. - frozenset((MHz(243),)), - ), - ), - ), -] - - -def get_radio(name: str) -> Radio: - """Returns the radio with the given name. - - Args: - name: Name of the radio to return. - - Returns: - The radio matching name. - - Raises: - KeyError: No matching radio was found. - """ - for radio in RADIOS: - if radio.name == name: - return radio - raise KeyError(f"Unknown radio: {name}") - - -class RadioRegistry: - """Manages allocation of radio channels. - - There's some room for improvement here. We could prefer to allocate - frequencies that are available to the fewest number of radios first, so - radios with wide bands like the AN/ARC-210 don't exhaust all the channels - available to narrower radios like the AN/ARC-186(V). In practice there are - probably plenty of channels, so we can deal with that later if we need to. - - We could also allocate using a larger increment, returning to smaller - increments each time the range is exhausted. This would help with the - previous problem, as the AN/ARC-186(V) would still have plenty of 25 kHz - increment channels left after the AN/ARC-210 moved on to the higher - frequencies. This would also look a little nicer than having every flight - allocated in the 30 MHz range. - """ - - # Not a real radio, but useful for allocating a channel usable for - # inter-flight communications. - # Uses AM as default Modulation - BLUFOR_UHF = Radio( - "BLUFOR UHF", (RadioRange(MHz(225), MHz(400), MHz(1), Modulation.AM),) - ) - - LINK_4 = Radio("Link 4", (RadioRange(MHz(300), MHz(325), kHz(100), Modulation.AM),)) - - def __init__(self) -> None: - self.allocated_channels: Set[RadioFrequency] = set() - self.radio_allocators: Dict[Radio, Iterator[RadioFrequency]] = {} - - radios = itertools.chain(RADIOS, [self.BLUFOR_UHF, self.LINK_4]) - for radio in radios: - self.radio_allocators[radio] = radio.range() - - def alloc_for_radio(self, radio: Radio) -> RadioFrequency: - """Allocates a radio channel tunable by the given radio. - - Args: - radio: The radio to allocate a channel for. - - Returns: - A radio channel compatible with the given radio. - - Raises: - OutOfChannelsError: All channels compatible with the given radio are - already allocated. - """ - allocator = self.radio_allocators[radio] - try: - while (channel := next(allocator)) in self.allocated_channels: - pass - self.reserve(channel) - return channel - except StopIteration: - # In the event of too many channel users, fail gracefully by reusing - # the last channel. - # https://github.com/dcs-liberation/dcs_liberation/issues/598 - channel = radio.last_channel - logging.warning( - f"No more free channels for {radio.name}. Reusing {channel}." - ) - return channel - - def alloc_uhf(self) -> RadioFrequency: - """Allocates a UHF radio channel suitable for inter-flight comms. - - Returns: - A UHF radio channel suitable for inter-flight comms. - - Raises: - OutOfChannelsError: All channels compatible with the given radio are - already allocated. - """ - return self.alloc_for_radio(self.BLUFOR_UHF) - - def alloc_link4(self) -> RadioFrequency: - return self.alloc_for_radio(self.LINK_4) - - def reserve(self, frequency: RadioFrequency) -> None: - """Reserves the given channel. - - Reserving a channel ensures that it will not be allocated in the future. - - Args: - frequency: The channel to reserve. - - Raises: - ChannelInUseError: The given frequency is already in use. - """ - if frequency in self.allocated_channels: - raise ChannelInUseError(frequency) - self.allocated_channels.add(frequency) diff --git a/game/radio/tacan.py b/game/radio/tacan.py deleted file mode 100644 index fb7bd42ff..000000000 --- a/game/radio/tacan.py +++ /dev/null @@ -1,113 +0,0 @@ -"""TACAN channel handling.""" -from __future__ import annotations - -import re -from dataclasses import dataclass -from enum import Enum -from typing import Dict, Iterator, Set - - -class TacanUsage(Enum): - TransmitReceive = "transmit receive" - AirToAir = "air to air" - - -class TacanBand(Enum): - X = "X" - Y = "Y" - - def range(self) -> Iterator["TacanChannel"]: - """Returns an iterator over the channels in this band.""" - return (TacanChannel(x, self) for x in range(1, 126 + 1)) - - def valid_channels(self, usage: TacanUsage) -> Iterator["TacanChannel"]: - for x in self.range(): - if x.number not in UNAVAILABLE[usage][self]: - yield x - - -# Avoid certain TACAN channels for various reasons -# https://forums.eagle.ru/topic/276390-datalink-issue/ -UNAVAILABLE = { - TacanUsage.TransmitReceive: { - TacanBand.X: set(range(2, 30 + 1)) | set(range(47, 63 + 1)), - TacanBand.Y: set(range(2, 30 + 1)) | set(range(64, 92 + 1)), - }, - TacanUsage.AirToAir: { - TacanBand.X: set(range(1, 36 + 1)) | set(range(64, 99 + 1)), - TacanBand.Y: set(range(1, 36 + 1)) | set(range(64, 99 + 1)), - }, -} - - -@dataclass(frozen=True) -class TacanChannel: - number: int - band: TacanBand - - def __str__(self) -> str: - return f"{self.number}{self.band.value}" - - @classmethod - def parse(cls, text: str) -> TacanChannel: - match = re.match(r"""^(\d{1,3})([XY])$""", text) - if match is None: - raise ValueError(f"Could not parse TACAN from {text}") - number = int(match.group(1)) - if not number: - raise ValueError("TACAN channel cannot be 0") - return TacanChannel(number, TacanBand(match.group(2))) - - -class OutOfTacanChannelsError(RuntimeError): - """Raised when all channels in this band have been allocated.""" - - def __init__(self, band: TacanBand) -> None: - super().__init__(f"No available channels in TACAN {band.value} band") - - -class TacanRegistry: - """Manages allocation of TACAN channels.""" - - def __init__(self) -> None: - self.allocated_channels: Set[TacanChannel] = set() - self.allocators: Dict[TacanBand, Dict[TacanUsage, Iterator[TacanChannel]]] = {} - - for band in TacanBand: - self.allocators[band] = {} - for usage in TacanUsage: - self.allocators[band][usage] = band.valid_channels(usage) - - def alloc_for_band( - self, band: TacanBand, intended_usage: TacanUsage - ) -> TacanChannel: - """Allocates a TACAN channel in the given band. - - Args: - band: The TACAN band to allocate a channel for. - intended_usage: What the caller intends to use the tacan channel for. - - Returns: - A TACAN channel in the given band. - - Raises: - OutOfTacanChannelsError: All channels compatible with the given radio are - already allocated. - """ - allocator = self.allocators[band][intended_usage] - try: - while (channel := next(allocator)) in self.allocated_channels: - pass - return channel - except StopIteration: - raise OutOfTacanChannelsError(band) - - def mark_unavailable(self, channel: TacanChannel) -> None: - """Reserves the given channel. - - Reserving a channel ensures that it will not be allocated in the future. - - Args: - channel: The channel to reserve. - """ - self.allocated_channels.add(channel) diff --git a/game/runways.py b/game/runways.py deleted file mode 100644 index 68d8ee2d2..000000000 --- a/game/runways.py +++ /dev/null @@ -1,146 +0,0 @@ -"""Runway information and selection.""" -from __future__ import annotations - -import logging -from dataclasses import dataclass -from typing import Iterator, Optional, TYPE_CHECKING - -from dcs.terrain.terrain import Airport, RunwayApproach - -from game.atcdata import AtcData -from game.dcs.beacons import BeaconType, Beacons -from game.radio.radios import RadioFrequency -from game.radio.tacan import TacanChannel -from game.utils import Heading -from game.weather.conditions import Conditions - -if TYPE_CHECKING: - from game.theater import ConflictTheater - - -@dataclass(frozen=True) -class RunwayData: - airfield_name: str - runway_heading: Heading - runway_name: str - atc: Optional[RadioFrequency] = None - tacan: Optional[TacanChannel] = None - tacan_callsign: Optional[str] = None - ils: Optional[RadioFrequency] = None - icls: Optional[int] = None - - @classmethod - def for_pydcs_runway_runway( - cls, - theater: ConflictTheater, - airport: Airport, - runway: RunwayApproach, - ) -> RunwayData: - """Creates RunwayData for the given runway of an airfield. - - Args: - theater: The theater the airport is in. - airport: The airfield the runway belongs to. - runway: The pydcs runway. - """ - atc: Optional[RadioFrequency] = None - tacan: Optional[TacanChannel] = None - tacan_callsign: Optional[str] = None - ils: Optional[RadioFrequency] = None - atc_radio = AtcData.from_pydcs(airport) - if atc_radio is not None: - atc = atc_radio.uhf - - for beacon_data in airport.beacons: - try: - beacon = Beacons.with_id(beacon_data.id, theater) - except KeyError: - # DCS data is not always correct. At time of writing, Hatzor in Sinai - # claims to have a beacon named airfield20_0, but the Sinai beacons.lua - # has no such beacon. - # See https://github.com/dcs-liberation/dcs_liberation/issues/3021. - logging.exception( - "Airport %s claims to have beacon %s but the map has no beacon " - "with that ID", - airport.name, - beacon_data.id, - ) - continue - if beacon.is_tacan: - tacan = beacon.tacan_channel - tacan_callsign = beacon.callsign - - for beacon_data in runway.beacons: - beacon = Beacons.with_id(beacon_data.id, theater) - if beacon.beacon_type is BeaconType.BEACON_TYPE_ILS_GLIDESLOPE: - ils = beacon.frequency - - return cls( - airfield_name=airport.name, - runway_heading=Heading(runway.heading), - runway_name=runway.name, - atc=atc, - tacan=tacan, - tacan_callsign=tacan_callsign, - ils=ils, - ) - - @classmethod - def for_pydcs_airport( - cls, theater: ConflictTheater, airport: Airport - ) -> Iterator[RunwayData]: - for runway in airport.runways: - yield cls.for_pydcs_runway_runway( - theater, - airport, - runway.main, - ) - yield cls.for_pydcs_runway_runway( - theater, - airport, - runway.opposite, - ) - - -class RunwayAssigner: - def __init__(self, conditions: Conditions): - self.conditions = conditions - - def angle_off_headwind(self, runway: RunwayData) -> Heading: - wind = Heading.from_degrees(self.conditions.weather.wind.at_0m.direction) - ideal_heading = wind.opposite - return runway.runway_heading.angle_between(ideal_heading) - - def get_preferred_runway( - self, theater: ConflictTheater, airport: Airport - ) -> RunwayData: - """Returns the preferred runway for the given airport. - - Right now we're only selecting runways based on whether or not - they have - ILS, but we could also choose based on wind conditions, or which - direction flight plans should follow. - """ - runways = list(RunwayData.for_pydcs_airport(theater, airport)) - - # Find the runway with the best headwind first. - best_runways = [runways[0]] - best_angle_off_headwind = self.angle_off_headwind(best_runways[0]) - for runway in runways[1:]: - angle_off_headwind = self.angle_off_headwind(runway) - if angle_off_headwind == best_angle_off_headwind: - best_runways.append(runway) - elif angle_off_headwind < best_angle_off_headwind: - best_runways = [runway] - best_angle_off_headwind = angle_off_headwind - - for runway in best_runways: - # But if there are multiple runways with the same heading, - # prefer - # and ILS capable runway. - if runway.ils is not None: - return runway - - # Otherwise the only difference between the two is the distance from - # parking, which we don't know, so just pick the first one. - return best_runways[0] diff --git a/game/savecompat.py b/game/savecompat.py deleted file mode 100644 index 6338d40fe..000000000 --- a/game/savecompat.py +++ /dev/null @@ -1,49 +0,0 @@ -"""Tools for aiding in save compat removal after compatibility breaks.""" -from collections.abc import Callable -from typing import TypeVar - -from game.version import MAJOR_VERSION - -ReturnT = TypeVar("ReturnT") - - -class DeprecatedSaveCompatError(RuntimeError): - def __init__(self, function_name: str) -> None: - super().__init__( - f"{function_name} has save compat code for a different major version." - ) - - -def has_save_compat_for( - major: int, -) -> Callable[[Callable[..., ReturnT]], Callable[..., ReturnT]]: - """Declares a function or method as having save compat code for a given version. - - If the function has save compatibility for the current major version, there is no - change in behavior. - - If the function has save compatibility for a *different* (future or past) major - version, DeprecatedSaveCompatError will be raised during startup. Since a break in - save compatibility is the definition of a major version break, there's no need to - keep around old save compat code; it only serves to mask initialization bugs. - - Args: - major: The major version for which the decorated function has save - compatibility. - - Returns: - The decorated function or method. - - Raises: - DeprecatedSaveCompatError: The decorated function has save compat code for - another version of liberation, and that code (and the decorator declaring it) - should be removed from this branch. - """ - - def decorator(func: Callable[..., ReturnT]) -> Callable[..., ReturnT]: - # Allow current and previous version to ease cherry-picking. - if major not in {MAJOR_VERSION - 1, MAJOR_VERSION}: - raise DeprecatedSaveCompatError(func.__name__) - return func - - return decorator diff --git a/game/scenery_group.py b/game/scenery_group.py deleted file mode 100644 index 64ea53010..000000000 --- a/game/scenery_group.py +++ /dev/null @@ -1,136 +0,0 @@ -from __future__ import annotations - -from typing import Iterable - -from dcs import Point -from dcs.triggers import TriggerZone, TriggerZoneCircular, TriggerZoneQuadPoint -from shapely.geometry import Point as ShapelyPoint, Polygon - -from game.theater.theatergroundobject import NAME_BY_CATEGORY - - -class SceneryGroup: - """Store information about a scenery objective.""" - - def __init__( - self, - name: str, - centroid: Point, - category: str, - target_zones: Iterable[TriggerZone], - ) -> None: - if not target_zones: - raise ValueError(f"{name} has no valid target zones") - - if category not in NAME_BY_CATEGORY: - raise ValueError( - f"Campaign objective {name} uses unknown scenery objective " - f"category: {category}" - ) - - self.name = name - self.centroid = centroid - self.category = category - self.target_zones = list(target_zones) - - @staticmethod - def category_of(group_zone: TriggerZone) -> str: - try: - # The first (1-indexed because lua) property of the group zone defines the - # TGO category. - category = group_zone.properties[1].get("value").lower() - except IndexError as ex: - raise RuntimeError( - f"{group_zone.name} does not define an objective category" - ) from ex - return category - - @staticmethod - def from_group_zone( - group_zone: TriggerZone, - unclaimed_target_zones: list[TriggerZone], - ) -> SceneryGroup: - return SceneryGroup( - group_zone.name, - group_zone.position, - SceneryGroup.category_of(group_zone), - SceneryGroup.claim_targets_for(group_zone, unclaimed_target_zones), - ) - - @staticmethod - def from_trigger_zones( - trigger_zones: Iterable[TriggerZone], - ) -> list[SceneryGroup]: - """Define scenery objectives based on their encompassing blue circle.""" - group_zones, target_zones = SceneryGroup.collect_scenery_zones(trigger_zones) - return [SceneryGroup.from_group_zone(z, target_zones) for z in group_zones] - - @staticmethod - def claim_targets_for( - group_zone: TriggerZone, - unclaimed_target_zones: list[TriggerZone], - ) -> list[TriggerZone]: - claimed_zones = [] - group_poly = SceneryGroup.poly_for_zone(group_zone) - for target in list(unclaimed_target_zones): - # If the target zone is a quad point, the position is arbitrary but visible - # to the designer. It is the "X" that marks the trigger zone in the ME. The - # ME seems to place this at the centroid of the zone. If that X is in the - # group zone, that's claimed. - # - # See https://github.com/pydcs/dcs/pull/243#discussion_r1001369516 for more - # info. - if group_poly.contains(ShapelyPoint(target.position.x, target.position.y)): - claimed_zones.append(target) - unclaimed_target_zones.remove(target) - return claimed_zones - - @staticmethod - def collect_scenery_zones( - zones: Iterable[TriggerZone], - ) -> tuple[list[TriggerZone], list[TriggerZone]]: - group_zones = [] - target_zones = [] - for zone in zones: - if SceneryGroup.is_group_zone(zone): - group_zones.append(zone) - if SceneryGroup.is_target_zone(zone): - target_zones.append(zone) - # No error on else. We're iterating over all the trigger zones in the miz, - # and others might be used for something else. - return group_zones, target_zones - - @staticmethod - def zone_has_color_rgb(zone: TriggerZone, r: float, g: float, b: float) -> bool: - # TriggerZone.color is a dict with keys 1 through 4, each being a component of - # RGBA. It's absurd that it's a dict, but that's a lua quirk that's leaking from - # pydcs. - return (zone.color[1], zone.color[2], zone.color[3]) == (r, g, b) - - @staticmethod - def is_group_zone(zone: TriggerZone) -> bool: - return SceneryGroup.zone_has_color_rgb(zone, r=0, g=0, b=1) - - @staticmethod - def is_target_zone(zone: TriggerZone) -> bool: - return SceneryGroup.zone_has_color_rgb(zone, r=1, g=1, b=1) - - @staticmethod - def poly_for_zone(zone: TriggerZone) -> Polygon: - if isinstance(zone, TriggerZoneCircular): - return SceneryGroup.poly_for_circular_zone(zone) - elif isinstance(zone, TriggerZoneQuadPoint): - return SceneryGroup.poly_for_quad_point_zone(zone) - else: - raise ValueError( - f"Invalid trigger zone type found for {zone.name}: " - f"{zone.__class__.__name__}" - ) - - @staticmethod - def poly_for_circular_zone(zone: TriggerZoneCircular) -> Polygon: - return ShapelyPoint(zone.position.x, zone.position.y).buffer(zone.radius) - - @staticmethod - def poly_for_quad_point_zone(zone: TriggerZoneQuadPoint) -> Polygon: - return Polygon([(p.x, p.y) for p in zone.verticies]) diff --git a/game/server/__init__.py b/game/server/__init__.py deleted file mode 100644 index 24ce56db7..000000000 --- a/game/server/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .dependencies import GameContext -from .eventstream import EventStream -from .server import Server diff --git a/game/server/app.py b/game/server/app.py deleted file mode 100644 index bb5822393..000000000 --- a/game/server/app.py +++ /dev/null @@ -1,47 +0,0 @@ -from fastapi import FastAPI -from fastapi.middleware.cors import CORSMiddleware - -from . import ( - controlpoints, - debuggeometries, - eventstream, - flights, - frontlines, - game, - iadsnetwork, - mapzones, - navmesh, - qt, - supplyroutes, - tgos, - waypoints, -) -from .settings import ServerSettings - -app = FastAPI() -app.include_router(controlpoints.router) -app.include_router(debuggeometries.router) -app.include_router(eventstream.router) -app.include_router(flights.router) -app.include_router(frontlines.router) -app.include_router(game.router) -app.include_router(mapzones.router) -app.include_router(navmesh.router) -app.include_router(qt.router) -app.include_router(supplyroutes.router) -app.include_router(tgos.router) -app.include_router(waypoints.router) -app.include_router(iadsnetwork.router) - - -origins = ["file://"] -if ServerSettings.get().cors_allow_debug_server: - origins.append("http://localhost:3000") - - -app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_methods=["*"], - allow_headers=["*"], -) diff --git a/game/server/combat/__init__.py b/game/server/combat/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/server/combat/models.py b/game/server/combat/models.py deleted file mode 100644 index c114e6ec7..000000000 --- a/game/server/combat/models.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from uuid import UUID - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint, LeafletPoly, ShapelyUtil -from game.sim.combat import FrozenCombat -from game.sim.combat.aircombat import AirCombat -from game.sim.combat.atip import AtIp -from game.sim.combat.defendingsam import DefendingSam -from game.theater import ConflictTheater - - -class FrozenCombatJs(BaseModel): - id: UUID - flight_position: LeafletPoint | None - target_positions: list[LeafletPoint] | None - footprint: list[LeafletPoly] | None - - class Config: - title = "FrozenCombat" - - @staticmethod - def for_combat(combat: FrozenCombat, theater: ConflictTheater) -> FrozenCombatJs: - if isinstance(combat, AirCombat): - return FrozenCombatJs( - id=combat.id, - flight_position=None, - target_positions=None, - footprint=ShapelyUtil.polys_to_leaflet(combat.footprint, theater), - ) - if isinstance(combat, AtIp): - return FrozenCombatJs( - id=combat.id, - flight_position=LeafletPoint.from_pydcs(combat.flight.position()), - target_positions=[ - LeafletPoint.from_pydcs(combat.flight.package.target.position) - ], - footprint=None, - ) - if isinstance(combat, DefendingSam): - return FrozenCombatJs( - id=combat.id, - flight_position=LeafletPoint.from_pydcs(combat.flight.position()), - target_positions=[ - LeafletPoint.from_pydcs(sam.position) for sam in combat.air_defenses - ], - footprint=None, - ) - raise NotImplementedError(f"Unhandled FrozenCombat type: {combat.__class__}") diff --git a/game/server/controlpoints/__init__.py b/game/server/controlpoints/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/controlpoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/controlpoints/models.py b/game/server/controlpoints/models.py deleted file mode 100644 index 9046c3006..000000000 --- a/game/server/controlpoints/models.py +++ /dev/null @@ -1,46 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from uuid import UUID - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint - -if TYPE_CHECKING: - from game import Game - from game.theater import ControlPoint - - -class ControlPointJs(BaseModel): - id: UUID - name: str - blue: bool - position: LeafletPoint - mobile: bool - destination: LeafletPoint | None - sidc: str - - class Config: - title = "ControlPoint" - - @staticmethod - def for_control_point(control_point: ControlPoint) -> ControlPointJs: - destination = None - if control_point.target_position is not None: - destination = LeafletPoint.from_pydcs(control_point.target_position) - return ControlPointJs( - id=control_point.id, - name=control_point.name, - blue=control_point.captured, - position=LeafletPoint.from_pydcs(control_point.position), - mobile=control_point.moveable and control_point.captured, - destination=destination, - sidc=str(control_point.sidc()), - ) - - @staticmethod - def all_in_game(game: Game) -> list[ControlPointJs]: - return [ - ControlPointJs.for_control_point(cp) for cp in game.theater.controlpoints - ] diff --git a/game/server/controlpoints/routes.py b/game/server/controlpoints/routes.py deleted file mode 100644 index b1c8f9edd..000000000 --- a/game/server/controlpoints/routes.py +++ /dev/null @@ -1,123 +0,0 @@ -from uuid import UUID - -from dcs import Point -from dcs.mapping import LatLng -from fastapi import APIRouter, Body, Depends, HTTPException, status -from starlette.responses import Response - -from game import Game -from .models import ControlPointJs -from ..dependencies import GameContext -from ..leaflet import LeafletPoint - -router: APIRouter = APIRouter(prefix="/control-points") - - -@router.get( - "/", operation_id="list_control_points", response_model=list[ControlPointJs] -) -def list_control_points( - game: Game = Depends(GameContext.require), -) -> list[ControlPointJs]: - return ControlPointJs.all_in_game(game) - - -@router.get( - "/{cp_id}", operation_id="get_control_point_by_id", response_model=ControlPointJs -) -def get_control_point( - cp_id: UUID, game: Game = Depends(GameContext.require) -) -> ControlPointJs: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - return ControlPointJs.for_control_point(cp) - - -@router.get( - "/{cp_id}/destination-in-range", - operation_id="control_point_destination_in_range", - response_model=bool, -) -def destination_in_range( - cp_id: UUID, lat: float, lng: float, game: Game = Depends(GameContext.require) -) -> bool: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - - point = Point.from_latlng(LatLng(lat, lng), game.theater.terrain) - return cp.destination_in_range(point) - - -@router.put( - "/{cp_id}/destination", - operation_id="set_control_point_destination", - status_code=status.HTTP_204_NO_CONTENT, - response_class=Response, -) -def set_destination( - cp_id: UUID, - destination: LeafletPoint = Body(..., title="destination"), - game: Game = Depends(GameContext.require), -) -> None: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - if not cp.moveable: - raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile") - if not cp.captured: - raise HTTPException( - status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player" - ) - - point = Point.from_latlng( - LatLng(destination.lat, destination.lng), game.theater.terrain - ) - if not cp.destination_in_range(point): - raise HTTPException( - status.HTTP_400_BAD_REQUEST, - detail=f"Cannot move {cp} more than " - f"{cp.max_move_distance.nautical_miles}nm.", - ) - cp.target_position = point - from .. import EventStream - - with EventStream.event_context() as events: - events.update_control_point(cp) - - -@router.put( - "/{cp_id}/cancel-travel", - operation_id="clear_control_point_destination", - status_code=status.HTTP_204_NO_CONTENT, - response_class=Response, -) -def cancel_travel(cp_id: UUID, game: Game = Depends(GameContext.require)) -> None: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - if not cp.moveable: - raise HTTPException(status.HTTP_403_FORBIDDEN, detail=f"{cp} is not mobile") - if not cp.captured: - raise HTTPException( - status.HTTP_403_FORBIDDEN, detail=f"{cp} is not owned by the player" - ) - - cp.target_position = None - from .. import EventStream - - with EventStream.event_context() as events: - events.update_control_point(cp) diff --git a/game/server/debuggeometries/__init__.py b/game/server/debuggeometries/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/debuggeometries/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/debuggeometries/models.py b/game/server/debuggeometries/models.py deleted file mode 100644 index 5d60c823f..000000000 --- a/game/server/debuggeometries/models.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import annotations - -from pydantic import BaseModel, Field - -from game import Game -from game.ato import Flight -from game.flightplan import HoldZoneGeometry, JoinZoneGeometry -from ..leaflet import LeafletLine, LeafletPoly, ShapelyUtil - - -class HoldZonesJs(BaseModel): - home_bubble: LeafletPoly = Field(alias="homeBubble") - target_bubble: LeafletPoly = Field(alias="targetBubble") - join_bubble: LeafletPoly = Field(alias="joinBubble") - excluded_zones: list[LeafletPoly] = Field(alias="excludedZones") - permissible_zones: list[LeafletPoly] = Field(alias="permissibleZones") - preferred_lines: list[LeafletLine] = Field(alias="preferredLines") - - class Config: - title = "HoldZones" - - @classmethod - def empty(cls) -> HoldZonesJs: - return HoldZonesJs( - homeBubble=[], - targetBubble=[], - joinBubble=[], - excludedZones=[], - permissibleZones=[], - preferredLines=[], - ) - - @classmethod - def for_flight(cls, flight: Flight, game: Game) -> HoldZonesJs: - target = flight.package.target - home = flight.departure - if flight.package.waypoints is None: - return HoldZonesJs.empty() - ip = flight.package.waypoints.ingress - join = flight.package.waypoints.join - geometry = HoldZoneGeometry( - target.position, home.position, ip, join, game.blue, game.theater - ) - return HoldZonesJs( - homeBubble=ShapelyUtil.poly_to_leaflet(geometry.home_bubble, game.theater), - targetBubble=ShapelyUtil.poly_to_leaflet( - geometry.target_bubble, game.theater - ), - joinBubble=ShapelyUtil.poly_to_leaflet(geometry.join_bubble, game.theater), - excludedZones=ShapelyUtil.polys_to_leaflet( - geometry.excluded_zones, game.theater - ), - permissibleZones=ShapelyUtil.polys_to_leaflet( - geometry.permissible_zones, game.theater - ), - preferredLines=ShapelyUtil.lines_to_leaflet( - geometry.preferred_lines, game.theater - ), - ) - - -class JoinZonesJs(BaseModel): - home_bubble: LeafletPoly = Field(alias="homeBubble") - target_bubble: LeafletPoly = Field(alias="targetBubble") - ip_bubble: LeafletPoly = Field(alias="ipBubble") - excluded_zones: list[LeafletPoly] = Field(alias="excludedZones") - permissible_zones: list[LeafletPoly] = Field(alias="permissibleZones") - preferred_lines: list[LeafletLine] = Field(alias="preferredLines") - - class Config: - title = "JoinZones" - - @classmethod - def empty(cls) -> JoinZonesJs: - return JoinZonesJs( - homeBubble=[], - targetBubble=[], - ipBubble=[], - excludedZones=[], - permissibleZones=[], - preferredLines=[], - ) - - @classmethod - def for_flight(cls, flight: Flight, game: Game) -> JoinZonesJs: - target = flight.package.target - home = flight.departure - if flight.package.waypoints is None: - return JoinZonesJs.empty() - ip = flight.package.waypoints.ingress - geometry = JoinZoneGeometry(target.position, home.position, ip, game.blue) - return JoinZonesJs( - homeBubble=ShapelyUtil.poly_to_leaflet(geometry.home_bubble, game.theater), - targetBubble=ShapelyUtil.poly_to_leaflet( - geometry.target_bubble, game.theater - ), - ipBubble=ShapelyUtil.poly_to_leaflet(geometry.ip_bubble, game.theater), - excludedZones=ShapelyUtil.polys_to_leaflet( - geometry.excluded_zones, game.theater - ), - permissibleZones=ShapelyUtil.polys_to_leaflet( - geometry.permissible_zones, game.theater - ), - preferredLines=ShapelyUtil.lines_to_leaflet( - geometry.preferred_lines, game.theater - ), - ) diff --git a/game/server/debuggeometries/routes.py b/game/server/debuggeometries/routes.py deleted file mode 100644 index f379b9955..000000000 --- a/game/server/debuggeometries/routes.py +++ /dev/null @@ -1,27 +0,0 @@ -from uuid import UUID - -from fastapi import APIRouter, Depends - -from game import Game -from game.server import GameContext -from .models import HoldZonesJs, JoinZonesJs - -router: APIRouter = APIRouter(prefix="/debug/waypoint-geometries") - - -@router.get( - "/hold/{flight_id}", operation_id="get_debug_hold_zones", response_model=HoldZonesJs -) -def hold_zones( - flight_id: UUID, game: Game = Depends(GameContext.require) -) -> HoldZonesJs: - return HoldZonesJs.for_flight(game.db.flights.get(flight_id), game) - - -@router.get( - "/join/{flight_id}", operation_id="get_debug_join_zones", response_model=JoinZonesJs -) -def join_zones( - flight_id: UUID, game: Game = Depends(GameContext.require) -) -> JoinZonesJs: - return JoinZonesJs.for_flight(game.db.flights.get(flight_id), game) diff --git a/game/server/dependencies.py b/game/server/dependencies.py deleted file mode 100644 index 3a9caaf4f..000000000 --- a/game/server/dependencies.py +++ /dev/null @@ -1,57 +0,0 @@ -from __future__ import annotations - -from typing import Callable, TYPE_CHECKING - -from game.theater import ControlPoint, MissionTarget, TheaterGroundObject - -if TYPE_CHECKING: - from game import Game - from qt_ui.models import GameModel - - -class GameContext: - _game_model: GameModel - - @classmethod - def set_model(cls, game_model: GameModel) -> None: - cls._game_model = game_model - - @classmethod - def get(cls) -> Game | None: - return cls._game_model.game - - @classmethod - def require(cls) -> Game: - if cls._game_model.game is None: - raise RuntimeError("GameContext has no Game set") - return cls._game_model.game - - @classmethod - def get_model(cls) -> GameModel: - return cls._game_model - - -class QtCallbacks: - def __init__( - self, - create_new_package: Callable[[MissionTarget], None], - show_tgo_info: Callable[[TheaterGroundObject], None], - show_control_point_info: Callable[[ControlPoint], None], - ) -> None: - self.create_new_package = create_new_package - self.show_tgo_info = show_tgo_info - self.show_control_point_info = show_control_point_info - - -class QtContext: - _callbacks: QtCallbacks - - @classmethod - def set_callbacks(cls, callbacks: QtCallbacks) -> None: - cls._callbacks = callbacks - - @classmethod - def get(cls) -> QtCallbacks: - if cls._callbacks is None: - raise RuntimeError("QtContext has no callbacks set") - return cls._callbacks diff --git a/game/server/eventstream/__init__.py b/game/server/eventstream/__init__.py deleted file mode 100644 index e06a9df81..000000000 --- a/game/server/eventstream/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .eventstream import EventStream -from .routes import router diff --git a/game/server/eventstream/eventstream.py b/game/server/eventstream/eventstream.py deleted file mode 100644 index 8db2000a8..000000000 --- a/game/server/eventstream/eventstream.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import annotations - -from asyncio import Queue -from collections.abc import Iterator -from contextlib import contextmanager - -from game.sim import GameUpdateEvents - - -class EventStream: - _queue: Queue[GameUpdateEvents] = Queue() - - @classmethod - def drain(cls) -> None: - while not cls._queue.empty(): - cls._queue.get_nowait() - cls._queue.task_done() - - @classmethod - async def put(cls, events: GameUpdateEvents) -> None: - await cls._queue.put(events) - - @classmethod - def put_nowait(cls, events: GameUpdateEvents) -> None: - # The queue has infinite size so this should never need to block anyway. If for - # some reason the queue is full this will throw QueueFull. - cls._queue.put_nowait(events) - - @classmethod - async def get(cls) -> GameUpdateEvents: - events = await cls._queue.get() - cls._queue.task_done() - return events - - @staticmethod - @contextmanager - def event_context() -> Iterator[GameUpdateEvents]: - events = GameUpdateEvents() - yield events - EventStream.put_nowait(events) diff --git a/game/server/eventstream/models.py b/game/server/eventstream/models.py deleted file mode 100644 index d1496b9ab..000000000 --- a/game/server/eventstream/models.py +++ /dev/null @@ -1,119 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from uuid import UUID - -from pydantic import BaseModel - -from game.server.combat.models import FrozenCombatJs -from game.server.controlpoints.models import ControlPointJs -from game.server.flights.models import FlightJs -from game.server.frontlines.models import FrontLineJs -from game.server.iadsnetwork.models import IadsConnectionJs -from game.server.leaflet import LeafletPoint -from game.server.mapzones.models import ThreatZonesJs, UnculledZoneJs -from game.server.navmesh.models import NavMeshJs -from game.server.tgos.models import TgoJs - -if TYPE_CHECKING: - from game import Game - from game.sim import GameUpdateEvents - - -class GameUpdateEventsJs(BaseModel): - updated_flight_positions: dict[UUID, LeafletPoint] - new_combats: list[FrozenCombatJs] - updated_combats: list[FrozenCombatJs] - ended_combats: list[UUID] - navmesh_updates: dict[bool, NavMeshJs] - updated_unculled_zones: list[UnculledZoneJs] - threat_zones_updated: dict[bool, ThreatZonesJs] - new_flights: list[FlightJs] - updated_flights: list[FlightJs] - deleted_flights: set[UUID] - selected_flight: UUID | None - deselected_flight: bool - updated_front_lines: list[FrontLineJs] - deleted_front_lines: set[UUID] - updated_tgos: list[TgoJs] - updated_control_points: list[ControlPointJs] - updated_iads: list[IadsConnectionJs] - deleted_iads: set[UUID] - reset_on_map_center: LeafletPoint | None - game_unloaded: bool - new_turn: bool - - @classmethod - def from_events( - cls, events: GameUpdateEvents, game: Game | None - ) -> GameUpdateEventsJs: - # We still need to be able to send update events when there is no game loaded - # because we need to send the unload event. - new_combats = [] - updated_combats = [] - updated_navmeshes = {} - updated_threat_zones = {} - updated_unculled_zones = [] - updated_iads = [] - updated_front_lines = [] - if game is not None: - new_combats = [ - FrozenCombatJs.for_combat(c, game.theater) for c in events.new_combats - ] - updated_combats = [ - FrozenCombatJs.for_combat(c, game.theater) - for c in events.updated_combats - ] - updated_navmeshes = { - player: NavMeshJs.from_navmesh(mesh, game) - for player, mesh in events.navmesh_updates.items() - } - updated_threat_zones = { - player: ThreatZonesJs.from_zones(zones, game.theater) - for player, zones in events.threat_zones_updated.items() - } - updated_unculled_zones = UnculledZoneJs.from_game(game) - for node in events.updated_iads: - updated_iads.extend(IadsConnectionJs.connections_for_node(node)) - updated_front_lines = [ - FrontLineJs.for_front_line(game.theater, f) - for f in events.updated_front_lines - ] - - reset_on_map_center: LeafletPoint | None = None - if events.reset_on_map_center is not None: - reset_on_map_center = LeafletPoint.from_pydcs(events.reset_on_map_center) - return GameUpdateEventsJs( - updated_flight_positions={ - f[0].id: LeafletPoint.from_pydcs(f[1]) - for f in events.updated_flight_positions - }, - new_combats=new_combats, - updated_combats=updated_combats, - ended_combats=[c.id for c in events.ended_combats], - navmesh_updates=updated_navmeshes, - updated_unculled_zones=updated_unculled_zones, - threat_zones_updated=updated_threat_zones, - new_flights=[ - FlightJs.for_flight(f, with_waypoints=True) for f in events.new_flights - ], - updated_flights=[ - FlightJs.for_flight(f, with_waypoints=True) - for f in events.updated_flights - ], - deleted_flights=events.deleted_flights, - selected_flight=events.selected_flight, - deselected_flight=events.deselected_flight, - updated_front_lines=updated_front_lines, - deleted_front_lines=events.deleted_front_lines, - updated_tgos=[TgoJs.for_tgo(tgo) for tgo in events.updated_tgos], - updated_control_points=[ - ControlPointJs.for_control_point(cp) - for cp in events.updated_control_points - ], - updated_iads=updated_iads, - deleted_iads=events.deleted_iads_connections, - reset_on_map_center=reset_on_map_center, - game_unloaded=events.game_unloaded, - new_turn=events.new_turn, - ) diff --git a/game/server/eventstream/routes.py b/game/server/eventstream/routes.py deleted file mode 100644 index d55b005bd..000000000 --- a/game/server/eventstream/routes.py +++ /dev/null @@ -1,54 +0,0 @@ -import asyncio -from asyncio import wait, Future - -from fastapi import APIRouter, WebSocket -from fastapi.encoders import jsonable_encoder - -from .eventstream import EventStream -from .models import GameUpdateEventsJs -from .. import GameContext - -router: APIRouter = APIRouter() - - -class ConnectionManager: - def __init__(self) -> None: - self.active_connections: list[WebSocket] = [] - - async def shutdown(self) -> None: - futures: list[Future[None]] = [] - for connection in self.active_connections: - futures.append(asyncio.create_task(connection.close())) - await wait(futures) - - async def connect(self, websocket: WebSocket) -> None: - await websocket.accept() - self.active_connections.append(websocket) - - def disconnect(self, websocket: WebSocket) -> None: - self.active_connections.remove(websocket) - - async def broadcast(self, events: GameUpdateEventsJs) -> None: - futures = [] - for connection in self.active_connections: - futures.append( - asyncio.create_task(connection.send_json(jsonable_encoder(events))) - ) - await wait(futures) - - -manager = ConnectionManager() - - -@router.websocket("/eventstream") -async def event_stream(websocket: WebSocket) -> None: - await manager.connect(websocket) - while True: - if not (events := await EventStream.get()).empty: - if events.shutting_down: - await manager.shutdown() - return - - await manager.broadcast( - GameUpdateEventsJs.from_events(events, GameContext.get()) - ) diff --git a/game/server/flights/__init__.py b/game/server/flights/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/flights/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/flights/models.py b/game/server/flights/models.py deleted file mode 100644 index f77b12551..000000000 --- a/game/server/flights/models.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from uuid import UUID - -from pydantic import BaseModel - -from game.ato.flightstate import InFlight -from game.ato.flightstate.killed import Killed -from game.server.leaflet import LeafletPoint -from game.server.waypoints.models import FlightWaypointJs -from game.server.waypoints.routes import waypoints_for_flight - -if TYPE_CHECKING: - from game import Game - from game.ato import Flight - - -class FlightJs(BaseModel): - id: UUID - blue: bool - position: LeafletPoint | None - sidc: str - waypoints: list[FlightWaypointJs] | None - - class Config: - title = "Flight" - - @staticmethod - def for_flight(flight: Flight, with_waypoints: bool) -> FlightJs: - # Don't provide a location for aircraft that aren't in the air. Later we can - # expand the model to include the state data for the UI so that it can make its - # own decisions about whether to draw the aircraft, but for now we'll filter - # here. - # - # We also draw dead aircraft so the player has some feedback about what's being - # lost. - position = None - if isinstance(flight.state, InFlight) or isinstance(flight.state, Killed): - position = LeafletPoint.from_pydcs(flight.position()) - waypoints = None - if with_waypoints: - waypoints = waypoints_for_flight(flight) - return FlightJs( - id=flight.id, - blue=flight.blue, - position=position, - sidc=str(flight.sidc()), - waypoints=waypoints, - ) - - @staticmethod - def all_in_game(game: Game, with_waypoints: bool) -> list[FlightJs]: - flights = [] - for coalition in game.coalitions: - for package in coalition.ato.packages: - for flight in package.flights: - flights.append(FlightJs.for_flight(flight, with_waypoints)) - return flights diff --git a/game/server/flights/routes.py b/game/server/flights/routes.py deleted file mode 100644 index de1f99bd7..000000000 --- a/game/server/flights/routes.py +++ /dev/null @@ -1,49 +0,0 @@ -from uuid import UUID - -from fastapi import APIRouter, Depends -from shapely.geometry import LineString, Point as ShapelyPoint - -from game import Game -from game.ato.flightplans.uizonedisplay import UiZoneDisplay -from game.server import GameContext -from game.server.flights.models import FlightJs -from game.server.leaflet import LeafletPoly, ShapelyUtil - -router: APIRouter = APIRouter(prefix="/flights") - - -@router.get("/", operation_id="list_flights", response_model=list[FlightJs]) -def list_flights( - with_waypoints: bool = False, game: Game = Depends(GameContext.require) -) -> list[FlightJs]: - return FlightJs.all_in_game(game, with_waypoints) - - -@router.get("/{flight_id}", operation_id="get_flight_by_id", response_model=FlightJs) -def get_flight( - flight_id: UUID, - with_waypoints: bool = False, - game: Game = Depends(GameContext.require), -) -> FlightJs: - flight = game.db.flights.get(flight_id) - return FlightJs.for_flight(flight, with_waypoints) - - -@router.get( - "/{flight_id}/commit-boundary", - operation_id="get_commit_boundary_for_flight", - response_model=LeafletPoly, -) -def commit_boundary( - flight_id: UUID, game: Game = Depends(GameContext.require) -) -> LeafletPoly: - flight = game.db.flights.get(flight_id) - if not isinstance(flight.flight_plan, UiZoneDisplay): - return [] - zone = flight.flight_plan.ui_zone() - if len(zone.points) == 1: - center = ShapelyPoint(zone.points[0].x, zone.points[0].y) - else: - center = LineString([ShapelyPoint(p.x, p.y) for p in zone.points]) - bubble = center.buffer(zone.radius.meters) - return ShapelyUtil.poly_to_leaflet(bubble, game.theater) diff --git a/game/server/frontlines/__init__.py b/game/server/frontlines/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/frontlines/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/frontlines/models.py b/game/server/frontlines/models.py deleted file mode 100644 index aef282e1b..000000000 --- a/game/server/frontlines/models.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from uuid import UUID - -from pydantic import BaseModel - -from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, -) -from game.server.leaflet import LeafletPoint - -if TYPE_CHECKING: - from game import Game - from game.theater import FrontLine, ConflictTheater - - -class FrontLineJs(BaseModel): - id: UUID - extents: list[LeafletPoint] - - class Config: - title = "FrontLine" - - @staticmethod - def for_front_line(theater: ConflictTheater, front_line: FrontLine) -> FrontLineJs: - bounds = FrontLineConflictDescription.frontline_bounds(front_line, theater) - return FrontLineJs( - id=front_line.id, - extents=[ - LeafletPoint.from_pydcs(bounds.left_position), - LeafletPoint.from_pydcs(bounds.right_position), - ], - ) - - @staticmethod - def all_in_game(game: Game) -> list[FrontLineJs]: - return [ - FrontLineJs.for_front_line(game.theater, f) - for f in game.theater.conflicts() - ] diff --git a/game/server/frontlines/routes.py b/game/server/frontlines/routes.py deleted file mode 100644 index c51b5715f..000000000 --- a/game/server/frontlines/routes.py +++ /dev/null @@ -1,25 +0,0 @@ -from uuid import UUID - -from fastapi import APIRouter, Depends - -from game import Game -from .models import FrontLineJs -from ..dependencies import GameContext - -router: APIRouter = APIRouter(prefix="/front-lines") - - -@router.get("/", operation_id="list_front_lines", response_model=list[FrontLineJs]) -def list_front_lines(game: Game = Depends(GameContext.require)) -> list[FrontLineJs]: - return FrontLineJs.all_in_game(game) - - -@router.get( - "/{front_line_id}", operation_id="get_front_line_by_id", response_model=FrontLineJs -) -def get_front_line( - front_line_id: UUID, game: Game = Depends(GameContext.require) -) -> FrontLineJs: - return FrontLineJs.for_front_line( - game.theater, game.db.front_lines.get(front_line_id) - ) diff --git a/game/server/game/__init__.py b/game/server/game/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/game/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/game/models.py b/game/server/game/models.py deleted file mode 100644 index 6ff76ebc2..000000000 --- a/game/server/game/models.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from pydantic import BaseModel - -from game.server.controlpoints.models import ControlPointJs -from game.server.flights.models import FlightJs -from game.server.frontlines.models import FrontLineJs -from game.server.iadsnetwork.models import IadsNetworkJs -from game.server.leaflet import LeafletPoint -from game.server.mapzones.models import ThreatZoneContainerJs, UnculledZoneJs -from game.server.navmesh.models import NavMeshesJs -from game.server.supplyroutes.models import SupplyRouteJs -from game.server.tgos.models import TgoJs - -if TYPE_CHECKING: - from game import Game - - -class GameJs(BaseModel): - control_points: list[ControlPointJs] - tgos: list[TgoJs] - supply_routes: list[SupplyRouteJs] - front_lines: list[FrontLineJs] - flights: list[FlightJs] - iads_network: IadsNetworkJs - threat_zones: ThreatZoneContainerJs - navmeshes: NavMeshesJs - map_center: LeafletPoint | None - unculled_zones: list[UnculledZoneJs] - - class Config: - title = "Game" - - @staticmethod - def from_game(game: Game) -> GameJs: - return GameJs( - control_points=ControlPointJs.all_in_game(game), - tgos=TgoJs.all_in_game(game), - supply_routes=SupplyRouteJs.all_in_game(game), - front_lines=FrontLineJs.all_in_game(game), - flights=FlightJs.all_in_game(game, with_waypoints=True), - iads_network=IadsNetworkJs.from_network(game.theater.iads_network), - threat_zones=ThreatZoneContainerJs.for_game(game), - navmeshes=NavMeshesJs.from_game(game), - map_center=LeafletPoint.from_pydcs( - game.theater.terrain.map_view_default.position - ), - unculled_zones=UnculledZoneJs.from_game(game), - ) diff --git a/game/server/game/routes.py b/game/server/game/routes.py deleted file mode 100644 index f960d485d..000000000 --- a/game/server/game/routes.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import APIRouter, Depends - -from game import Game -from game.server import GameContext -from .models import GameJs - -router: APIRouter = APIRouter(prefix="/game") - - -@router.get("/", operation_id="get_game_state", response_model=GameJs) -def game_state(game: Game | None = Depends(GameContext.get)) -> GameJs | None: - if game is None: - return None - return GameJs.from_game(game) diff --git a/game/server/iadsnetwork/__init__.py b/game/server/iadsnetwork/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/iadsnetwork/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/iadsnetwork/models.py b/game/server/iadsnetwork/models.py deleted file mode 100644 index 68e490fa5..000000000 --- a/game/server/iadsnetwork/models.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from uuid import UUID - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint -from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode, IadsNetwork - - -class IadsConnectionJs(BaseModel): - id: UUID - points: list[LeafletPoint] - node: UUID - connected: UUID - active: bool - blue: bool - is_power: bool - - class Config: - title = "IadsConnection" - - @staticmethod - def connections_for_tgo( - tgo_id: UUID, network: IadsNetwork - ) -> list[IadsConnectionJs]: - for node in network.nodes: - if node.group.ground_object.id == tgo_id: - return IadsConnectionJs.connections_for_node(node) - return [] - - @staticmethod - def connections_for_node(network_node: IadsNetworkNode) -> list[IadsConnectionJs]: - iads_connections = [] - tgo = network_node.group.ground_object - for id, connection in network_node.connections.items(): - if ( - not connection.iads_role.is_secondary_node - or connection.ground_object.is_friendly(True) != tgo.is_friendly(True) - ): - # Skip connections to non secondary nodes (for example PD) - # and connections which are not from same coalition - continue - iads_connections.append( - IadsConnectionJs( - id=id, - points=[ - LeafletPoint.from_pydcs(tgo.position), - LeafletPoint.from_pydcs(connection.ground_object.position), - ], - node=tgo.id, - connected=connection.ground_object.id, - active=( - network_node.group.alive_units > 0 - and connection.alive_units > 0 - ), - blue=tgo.is_friendly(True), - is_power="power" - in [tgo.category, connection.ground_object.category], - ) - ) - return iads_connections - - -class IadsNetworkJs(BaseModel): - advanced: bool - connections: list[IadsConnectionJs] - - class Config: - title = "IadsNetwork" - - @staticmethod - def from_network(network: IadsNetwork) -> IadsNetworkJs: - iads_connections = [] - for primary_node in network.nodes: - iads_connections.extend(IadsConnectionJs.connections_for_node(primary_node)) - return IadsNetworkJs( - advanced=network.advanced_iads, connections=iads_connections - ) diff --git a/game/server/iadsnetwork/routes.py b/game/server/iadsnetwork/routes.py deleted file mode 100644 index 81cd28b1a..000000000 --- a/game/server/iadsnetwork/routes.py +++ /dev/null @@ -1,26 +0,0 @@ -from uuid import UUID -from fastapi import APIRouter, Depends - -from game import Game -from .models import IadsConnectionJs, IadsNetworkJs -from ..dependencies import GameContext - -router: APIRouter = APIRouter(prefix="/iads-network") - - -@router.get("/", operation_id="get_iads_network", response_model=IadsNetworkJs) -def get_iads_network( - game: Game = Depends(GameContext.require), -) -> IadsNetworkJs: - return IadsNetworkJs.from_network(game.theater.iads_network) - - -@router.get( - "/for-tgo/{tgo_id}", - operation_id="get_iads_connections_for_tgo", - response_model=list[IadsConnectionJs], -) -def get_iads_connections_for_tgo( - tgo_id: UUID, game: Game = Depends(GameContext.require) -) -> list[IadsConnectionJs]: - return IadsConnectionJs.connections_for_tgo(tgo_id, game.theater.iads_network) diff --git a/game/server/leaflet.py b/game/server/leaflet.py deleted file mode 100644 index bd9a1f183..000000000 --- a/game/server/leaflet.py +++ /dev/null @@ -1,79 +0,0 @@ -from __future__ import annotations - -from typing import Union - -from dcs import Point -from dcs.mapping import LatLng -from pydantic import BaseModel -from shapely.geometry import LineString, MultiLineString, MultiPolygon, Polygon - -from game.theater import ConflictTheater - - -class LeafletPoint(BaseModel): - lat: float - lng: float - - class Config: - orm_mode = True - - title = "LatLng" - - @staticmethod - def from_pydcs(point: Point) -> LeafletPoint: - latlng = point.latlng() - return LeafletPoint(lat=latlng.lat, lng=latlng.lng) - - -LeafletLine = list[LeafletPoint] - - -# Leaflet allows either a single array of latlng to define the boundary, or an array of -# arrays of latlngs, with the first array being the boundary and the rest defining -# holes. To avoid the UI needing to test for which type of polygon we send, we always -# use the array of arrays type, even for geometries without holes. -# https://leafletjs.com/reference.html#polygon -LeafletPoly = list[LeafletLine] - - -class ShapelyUtil: - @staticmethod - def latlng_to_leaflet(latlng: LatLng) -> LeafletPoint: - return LeafletPoint(lat=latlng.lat, lng=latlng.lng) - - @classmethod - def poly_to_leaflet(cls, poly: Polygon, theater: ConflictTheater) -> LeafletPoly: - if poly.is_empty: - return [] - try: - lines = poly.boundary.geoms - except AttributeError: - lines = [poly.boundary] - return cls.lines_to_leaflet(MultiLineString(lines), theater) - - @classmethod - def polys_to_leaflet( - cls, poly: Union[Polygon, MultiPolygon], theater: ConflictTheater - ) -> list[LeafletPoly]: - if isinstance(poly, MultiPolygon): - polys = poly.geoms - else: - polys = [poly] - return [cls.poly_to_leaflet(poly, theater) for poly in polys] - - @classmethod - def line_to_leaflet(cls, line: LineString, theater: ConflictTheater) -> LeafletLine: - return [ - cls.latlng_to_leaflet(Point(x, y, theater.terrain).latlng()) - for x, y in line.coords - ] - - @classmethod - def lines_to_leaflet( - cls, line_string: MultiLineString | LineString, theater: ConflictTheater - ) -> list[LeafletLine]: - if isinstance(line_string, MultiLineString): - lines = line_string.geoms - else: - lines = [line_string] - return [cls.line_to_leaflet(line, theater) for line in lines] diff --git a/game/server/mapzones/__init__.py b/game/server/mapzones/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/mapzones/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/mapzones/models.py b/game/server/mapzones/models.py deleted file mode 100644 index 335e3dd0d..000000000 --- a/game/server/mapzones/models.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint, LeafletPoly, ShapelyUtil -from game.theater import ConflictTheater -from game.threatzones import ThreatZones - -if TYPE_CHECKING: - from game import Game - - -class MapZonesJs(BaseModel): - inclusion: list[LeafletPoly] - exclusion: list[LeafletPoly] - sea: list[LeafletPoly] - - class Config: - title = "MapZones" - - @classmethod - def empty(cls) -> MapZonesJs: - return MapZonesJs(inclusion=[], exclusion=[], sea=[]) - - -class UnculledZoneJs(BaseModel): - position: LeafletPoint - radius: float - - class Config: - title = "UnculledZone" - - @staticmethod - def from_game(game: Game) -> list[UnculledZoneJs]: - return [ - UnculledZoneJs( - position=LeafletPoint.from_pydcs(zone), - radius=game.settings.perf_culling_distance * 1000, - ) - for zone in game.get_culling_zones() - ] - - -class ThreatZonesJs(BaseModel): - full: list[LeafletPoly] - aircraft: list[LeafletPoly] - air_defenses: list[LeafletPoly] - radar_sams: list[LeafletPoly] - - class Config: - title = "ThreatZones" - - @classmethod - def from_zones(cls, zones: ThreatZones, theater: ConflictTheater) -> ThreatZonesJs: - return ThreatZonesJs( - full=ShapelyUtil.polys_to_leaflet(zones.all, theater), - aircraft=ShapelyUtil.polys_to_leaflet(zones.airbases, theater), - air_defenses=ShapelyUtil.polys_to_leaflet(zones.air_defenses, theater), - radar_sams=ShapelyUtil.polys_to_leaflet(zones.radar_sam_threats, theater), - ) - - -class ThreatZoneContainerJs(BaseModel): - blue: ThreatZonesJs - red: ThreatZonesJs - - class Config: - title = "ThreatZoneContainer" - - @staticmethod - def for_game(game: Game) -> ThreatZoneContainerJs: - return ThreatZoneContainerJs( - blue=ThreatZonesJs.from_zones( - game.threat_zone_for(player=True), game.theater - ), - red=ThreatZonesJs.from_zones( - game.threat_zone_for(player=False), game.theater - ), - ) diff --git a/game/server/mapzones/routes.py b/game/server/mapzones/routes.py deleted file mode 100644 index af006139a..000000000 --- a/game/server/mapzones/routes.py +++ /dev/null @@ -1,55 +0,0 @@ -import logging - -from fastapi import APIRouter, Depends, HTTPException, status - -from game import Game -from game.server import GameContext -from .models import MapZonesJs, ThreatZoneContainerJs, UnculledZoneJs -from ..leaflet import ShapelyUtil - -router: APIRouter = APIRouter(prefix="/map-zones") - - -@router.get("/terrain", operation_id="get_terrain_zones", response_model=MapZonesJs) -def get_terrain(game: Game = Depends(GameContext.require)) -> MapZonesJs: - if game.theater.terrain.name == "Falklands": - # The new high fidelity landmap is far too expensive to send to the UI. - # Converting all the points from DCS X/Y to lat/lng and then serializing all - # that data takes minutes and gigabytes (!!) of RAM. - # - # It's not clear how much the rest of Liberation is affected by the landmap - # complexity yet. If the rest of the game is tolerable we will need to start - # baking images of the landmap that can be used as an overlay in the UI rather - # than drawing it from each point. - logging.debug( - "Not sending landmap to the UI for Falklands because it's too slow" - ) - return MapZonesJs.empty() - - zones = game.theater.landmap - if zones is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - - return MapZonesJs( - inclusion=ShapelyUtil.polys_to_leaflet(zones.inclusion_zones, game.theater), - exclusion=ShapelyUtil.polys_to_leaflet(zones.exclusion_zones, game.theater), - sea=ShapelyUtil.polys_to_leaflet(zones.sea_zones, game.theater), - ) - - -@router.get( - "/unculled", operation_id="list_unculled_zones", response_model=list[UnculledZoneJs] -) -def get_unculled_zones( - game: Game = Depends(GameContext.require), -) -> list[UnculledZoneJs]: - return UnculledZoneJs.from_game(game) - - -@router.get( - "/threats", operation_id="get_threat_zones", response_model=ThreatZoneContainerJs -) -def get_threat_zones( - game: Game = Depends(GameContext.require), -) -> ThreatZoneContainerJs: - return ThreatZoneContainerJs.for_game(game) diff --git a/game/server/navmesh/__init__.py b/game/server/navmesh/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/navmesh/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/navmesh/models.py b/game/server/navmesh/models.py deleted file mode 100644 index 69c972754..000000000 --- a/game/server/navmesh/models.py +++ /dev/null @@ -1,53 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoly, ShapelyUtil - -if TYPE_CHECKING: - from game import Game - from game.navmesh import NavMesh - - -class NavMeshPolyJs(BaseModel): - poly: LeafletPoly - threatened: bool - - class Config: - title = "NavMeshPoly" - - -class NavMeshJs(BaseModel): - polys: list[NavMeshPolyJs] - - class Config: - title = "NavMesh" - - @staticmethod - def from_navmesh(navmesh: NavMesh, game: Game) -> NavMeshJs: - return NavMeshJs( - polys=[ - NavMeshPolyJs( - poly=ShapelyUtil.poly_to_leaflet(p.poly, game.theater), - threatened=p.threatened, - ) - for p in navmesh.polys - ] - ) - - -class NavMeshesJs(BaseModel): - blue: NavMeshJs - red: NavMeshJs - - class Config: - title = "NavMeshes" - - @staticmethod - def from_game(game: Game) -> NavMeshesJs: - return NavMeshesJs( - blue=NavMeshJs.from_navmesh(game.blue.nav_mesh, game), - red=NavMeshJs.from_navmesh(game.red.nav_mesh, game), - ) diff --git a/game/server/navmesh/routes.py b/game/server/navmesh/routes.py deleted file mode 100644 index 01b390e1c..000000000 --- a/game/server/navmesh/routes.py +++ /dev/null @@ -1,13 +0,0 @@ -from fastapi import APIRouter, Depends - -from game import Game -from game.server import GameContext -from .models import NavMeshJs - -router: APIRouter = APIRouter(prefix="/navmesh") - - -@router.get("/", operation_id="get_navmesh", response_model=NavMeshJs) -def get(for_player: bool, game: Game = Depends(GameContext.require)) -> NavMeshJs: - mesh = game.coalition_for(for_player).nav_mesh - return NavMeshJs.from_navmesh(mesh, game) diff --git a/game/server/qt/__init__.py b/game/server/qt/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/qt/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/qt/routes.py b/game/server/qt/routes.py deleted file mode 100644 index c6169297f..000000000 --- a/game/server/qt/routes.py +++ /dev/null @@ -1,85 +0,0 @@ -from uuid import UUID - -from fastapi import APIRouter, Depends, HTTPException, status - -from game import Game -from ..dependencies import GameContext, QtCallbacks, QtContext - -router: APIRouter = APIRouter(prefix="/qt") - - -@router.post( - "/create-package/front-line/{front_line_id}", - operation_id="open_new_front_line_package_dialog", - status_code=status.HTTP_200_OK, -) -def new_front_line_package( - front_line_id: UUID, - game: Game = Depends(GameContext.require), - qt: QtCallbacks = Depends(QtContext.get), -) -> None: - qt.create_new_package(game.db.front_lines.get(front_line_id)) - - -@router.post( - "/create-package/tgo/{tgo_id}", - operation_id="open_new_tgo_package_dialog", - status_code=status.HTTP_200_OK, -) -def new_tgo_package( - tgo_id: UUID, - game: Game = Depends(GameContext.require), - qt: QtCallbacks = Depends(QtContext.get), -) -> None: - qt.create_new_package(game.db.tgos.get(tgo_id)) - - -@router.post( - "/info/tgo/{tgo_id}", - operation_id="open_tgo_info_dialog", - status_code=status.HTTP_200_OK, -) -def show_tgo_info( - tgo_id: UUID, - game: Game = Depends(GameContext.require), - qt: QtCallbacks = Depends(QtContext.get), -) -> None: - qt.show_tgo_info(game.db.tgos.get(tgo_id)) - - -@router.post( - "/create-package/control-point/{cp_id}", - operation_id="open_new_control_point_package_dialog", - status_code=status.HTTP_200_OK, -) -def new_cp_package( - cp_id: UUID, - game: Game = Depends(GameContext.require), - qt: QtCallbacks = Depends(QtContext.get), -) -> None: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - qt.create_new_package(cp) - - -@router.post( - "/info/control-point/{cp_id}", - operation_id="open_control_point_info_dialog", - status_code=status.HTTP_200_OK, -) -def show_control_point_info( - cp_id: UUID, - game: Game = Depends(GameContext.require), - qt: QtCallbacks = Depends(QtContext.get), -) -> None: - cp = game.theater.find_control_point_by_id(cp_id) - if cp is None: - raise HTTPException( - status.HTTP_404_NOT_FOUND, - detail=f"Game has no control point with ID {cp_id}", - ) - qt.show_control_point_info(cp) diff --git a/game/server/security.py b/game/server/security.py deleted file mode 100644 index de61bdc9a..000000000 --- a/game/server/security.py +++ /dev/null @@ -1,15 +0,0 @@ -import secrets - -from fastapi import HTTPException, Security, status -from fastapi.security import APIKeyHeader - -API_KEY_HEADER = APIKeyHeader(name="X-API-Key") - - -class ApiKeyManager: - KEY = secrets.token_urlsafe() - - @classmethod - def verify(cls, api_key_header: str = Security(API_KEY_HEADER)) -> None: - if api_key_header != cls.KEY: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) diff --git a/game/server/server.py b/game/server/server.py deleted file mode 100644 index 3cd47eb2d..000000000 --- a/game/server/server.py +++ /dev/null @@ -1,40 +0,0 @@ -import time -from collections.abc import Iterator -from contextlib import contextmanager -from threading import Thread - -import uvicorn -from uvicorn import Config - -from game.server import EventStream -from game.server.app import app -from game.server.settings import ServerSettings -from game.sim import GameUpdateEvents - - -class Server(uvicorn.Server): - def __init__(self) -> None: - super().__init__( - Config( - app=app, - host=ServerSettings.get().server_bind_address, - port=ServerSettings.get().server_port, - # Configured explicitly with default_logging.yaml or logging.yaml. - log_config=None, - ) - ) - - @contextmanager - def run_in_thread(self) -> Iterator[None]: - # This relies on undocumented behavior, but it is what the developer recommends: - # https://github.com/encode/uvicorn/issues/742 - thread = Thread(target=self.run) - thread.start() - try: - while not self.started: - time.sleep(1e-3) - yield - finally: - self.should_exit = True - EventStream.put_nowait(GameUpdateEvents().shut_down()) - thread.join() diff --git a/game/server/settings.py b/game/server/settings.py deleted file mode 100644 index f24ae182c..000000000 --- a/game/server/settings.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations - -from functools import lru_cache - -from pydantic_settings import BaseSettings - - -class ServerSettings(BaseSettings): - """Settings controlling server behavior. - - The values listed here will be automatically modified based on the environment. e.g. - running with SERVER_BIND_ADDRESS=0.0.0.0 will cause the server to bind to all - interfaces. - - https://fastapi.tiangolo.com/advanced/settings - """ - - # WARNING: Be extremely cautious exposing the server to other machines. As there is - # no client/server workflow yet, security has not been a focus. - server_bind_address: str = "::1" - - # This (and the address) will be passed the the front end as a query parameter. - server_port: int = 16880 - - # Enable to allow cross-origin requests from http://localhost:3000. - cors_allow_debug_server: bool = False - - class Config: - env_file = "serverconfig.env" - - @classmethod - @lru_cache - def get(cls) -> ServerSettings: - return cls() diff --git a/game/server/supplyroutes/__init__.py b/game/server/supplyroutes/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/supplyroutes/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/supplyroutes/models.py b/game/server/supplyroutes/models.py deleted file mode 100644 index 03ae7c27c..000000000 --- a/game/server/supplyroutes/models.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import annotations - -import uuid -from typing import Any, TYPE_CHECKING -from uuid import UUID - -from dcs import Point -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint - -if TYPE_CHECKING: - from game import Game - from game.theater import ControlPoint - from game.transfers import MultiGroupTransport, TransportMap - - -class TransportFinder: - def __init__( - self, game: Game, control_point_a: ControlPoint, control_point_b: ControlPoint - ) -> None: - self.game = game - self.control_point_a = control_point_a - self.control_point_b = control_point_b - - def find_in_transport_map( - self, transport_map: TransportMap[Any] - ) -> list[MultiGroupTransport]: - transports = [] - transport = transport_map.find_transport( - self.control_point_a, self.control_point_b - ) - if transport is not None: - transports.append(transport) - transport = transport_map.find_transport( - self.control_point_b, self.control_point_a - ) - if transport is not None: - transports.append(transport) - return transports - - def find_transports(self, sea_route: bool) -> list[MultiGroupTransport]: - if sea_route: - return self.find_in_transport_map( - self.game.blue.transfers.cargo_ships - ) + self.find_in_transport_map(self.game.red.transfers.cargo_ships) - return self.find_in_transport_map( - self.game.blue.transfers.convoys - ) + self.find_in_transport_map(self.game.red.transfers.convoys) - - def describe_active_transports(self, sea_route: bool) -> list[str]: - transports = self.find_transports(sea_route) - if not transports: - return [] - - descriptions = [] - for transport in transports: - units = "units" if transport.size > 1 else "unit" - descriptions.append( - f"{transport.size} {units} transferring from {transport.origin} to " - f"{transport.destination}" - ) - return descriptions - - -class SupplyRouteJs(BaseModel): - id: UUID - points: list[LeafletPoint] - front_active: bool - is_sea: bool - blue: bool - active_transports: list[str] - - class Config: - title = "SupplyRoute" - - @staticmethod - def for_link( - game: Game, a: ControlPoint, b: ControlPoint, points: list[Point], sea: bool - ) -> SupplyRouteJs: - return SupplyRouteJs( - # Although these are not persistent objects in the backend, the frontend - # needs unique IDs for anything that it will use in a list. That means that - # any data that we expose as a list most likely needs a unique ID. List - # indexes are **not** sufficient as IDs across game loads, as any indexes - # that persist between games will not be updated in the UI. - # - # Generating a UUID for these ephemeral objects is awkward, but does not - # cause any issues since the only thing the ID is used for is to - # disambiguate objects across save games. - # - # https://reactjs.org/docs/lists-and-keys.html#keys - # https://github.com/dcs-liberation/dcs_liberation/issues/2167 - id=uuid.uuid4(), - points=[LeafletPoint.from_pydcs(p) for p in points], - front_active=not sea and a.front_is_active(b), - is_sea=sea, - blue=a.captured, - active_transports=TransportFinder(game, a, b).describe_active_transports( - sea - ), - ) - - @staticmethod - def all_in_game(game: Game) -> list[SupplyRouteJs]: - seen = set() - routes = [] - for control_point in game.theater.controlpoints: - seen.add(control_point) - for destination, route in control_point.convoy_routes.items(): - if destination in seen: - continue - routes.append( - SupplyRouteJs.for_link( - game, control_point, destination, list(route), sea=False - ) - ) - for destination, route in control_point.shipping_lanes.items(): - if destination in seen: - continue - if not destination.is_friendly_to(control_point): - continue - routes.append( - SupplyRouteJs.for_link( - game, control_point, destination, list(route), sea=True - ) - ) - return routes diff --git a/game/server/supplyroutes/routes.py b/game/server/supplyroutes/routes.py deleted file mode 100644 index 675b5ba54..000000000 --- a/game/server/supplyroutes/routes.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import APIRouter, Depends - -from game import Game -from .models import SupplyRouteJs -from ..dependencies import GameContext - -router: APIRouter = APIRouter(prefix="/supply-routes") - - -@router.get("/", operation_id="list_supply_routes", response_model=list[SupplyRouteJs]) -def list_supply_routes( - game: Game = Depends(GameContext.require), -) -> list[SupplyRouteJs]: - return SupplyRouteJs.all_in_game(game) diff --git a/game/server/tgos/__init__.py b/game/server/tgos/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/tgos/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/tgos/models.py b/game/server/tgos/models.py deleted file mode 100644 index c28068dd7..000000000 --- a/game/server/tgos/models.py +++ /dev/null @@ -1,56 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING -from uuid import UUID - -from pydantic import BaseModel - -from game.server.leaflet import LeafletPoint - -if TYPE_CHECKING: - from game import Game - from game.theater import TheaterGroundObject - - -class TgoJs(BaseModel): - id: UUID - name: str - control_point_name: str - category: str - blue: bool - position: LeafletPoint - units: list[str] # TODO: Event stream - threat_ranges: list[float] # TODO: Event stream - detection_ranges: list[float] # TODO: Event stream - dead: bool # TODO: Event stream - sidc: str # TODO: Event stream - - class Config: - title = "Tgo" - - @staticmethod - def for_tgo(tgo: TheaterGroundObject) -> TgoJs: - threat_ranges = [group.max_threat_range().meters for group in tgo.groups] - detection_ranges = [group.max_detection_range().meters for group in tgo.groups] - return TgoJs( - id=tgo.id, - name=tgo.name, - control_point_name=tgo.control_point.name, - category=tgo.category, - blue=tgo.control_point.captured, - position=LeafletPoint.from_pydcs(tgo.position), - units=[unit.display_name for unit in tgo.units], - threat_ranges=threat_ranges, - detection_ranges=detection_ranges, - dead=tgo.is_dead, - sidc=str(tgo.sidc()), - ) - - @staticmethod - def all_in_game(game: Game) -> list[TgoJs]: - tgos = [] - for control_point in game.theater.controlpoints: - for tgo in control_point.connected_objectives: - if not tgo.is_control_point: - tgos.append(TgoJs.for_tgo(tgo)) - return tgos diff --git a/game/server/tgos/routes.py b/game/server/tgos/routes.py deleted file mode 100644 index cc84dc229..000000000 --- a/game/server/tgos/routes.py +++ /dev/null @@ -1,19 +0,0 @@ -from uuid import UUID - -from fastapi import APIRouter, Depends - -from game import Game -from .models import TgoJs -from ..dependencies import GameContext - -router: APIRouter = APIRouter(prefix="/tgos") - - -@router.get("/", operation_id="list_tgos", response_model=list[TgoJs]) -def list_tgos(game: Game = Depends(GameContext.require)) -> list[TgoJs]: - return TgoJs.all_in_game(game) - - -@router.get("/{tgo_id}", operation_id="get_tgo_by_id", response_model=TgoJs) -def get_tgo(tgo_id: UUID, game: Game = Depends(GameContext.require)) -> TgoJs: - return TgoJs.for_tgo(game.db.tgos.get(tgo_id)) diff --git a/game/server/waypoints/__init__.py b/game/server/waypoints/__init__.py deleted file mode 100644 index 3a27ef1c7..000000000 --- a/game/server/waypoints/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .routes import router diff --git a/game/server/waypoints/models.py b/game/server/waypoints/models.py deleted file mode 100644 index 8b9a1e4ce..000000000 --- a/game/server/waypoints/models.py +++ /dev/null @@ -1,92 +0,0 @@ -from __future__ import annotations - -from pydantic import BaseModel - -from game.ato import Flight, FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.server.leaflet import LeafletPoint - - -def timing_info(flight: Flight, waypoint_idx: int) -> str: - if waypoint_idx == 0: - return f"Depart T+{flight.flight_plan.takeoff_time()}" - - waypoint = flight.flight_plan.waypoints[waypoint_idx - 1] - prefix = "TOT" - time = flight.flight_plan.tot_for_waypoint(waypoint) - if time is None: - prefix = "Depart" - time = flight.flight_plan.depart_time_for_waypoint(waypoint) - if time is None: - return "" - return f"{prefix} {time}" - - -class FlightWaypointJs(BaseModel): - name: str - position: LeafletPoint - altitude_ft: float - altitude_reference: str - is_movable: bool - should_mark: bool - include_in_path: bool - timing: str - - class Config: - title = "Waypoint" - - @staticmethod - def for_waypoint( - waypoint: FlightWaypoint, flight: Flight, waypoint_idx: int - ) -> FlightWaypointJs: - # Target *points* are the exact location of a unit, whereas the target area is - # only the center of the objective. Allow moving the latter since its exact - # location isn't very important. - # - # Landing, and divert should be changed in the flight settings UI, takeoff - # cannot be changed because that's where the plane is. - # - # Moving the bullseye reference only makes it wrong. - is_movable = waypoint.waypoint_type not in { - FlightWaypointType.BULLSEYE, - FlightWaypointType.DIVERT, - FlightWaypointType.LANDING_POINT, - FlightWaypointType.TAKEOFF, - FlightWaypointType.TARGET_POINT, - } - - # We don't need a marker for the departure waypoint (and it's likely - # coincident with the landing waypoint, so hard to see). We do want to draw - # the path from it though. - # - # We also don't need the landing waypoint since we'll be drawing that path - # as well, and it's clear what it is, and only obscured the CP icon. - # - # The divert waypoint also obscures the CP. We don't draw the path to it, - # but it can be seen in the flight settings page, so it's not really a - # problem to exclude it. - # - # Bullseye ought to be (but currently isn't) drawn *once* rather than as a - # flight waypoint. - should_mark = waypoint.waypoint_type not in { - FlightWaypointType.BULLSEYE, - FlightWaypointType.DIVERT, - FlightWaypointType.LANDING_POINT, - FlightWaypointType.TAKEOFF, - } - - include_in_path = waypoint.waypoint_type not in { - FlightWaypointType.BULLSEYE, - FlightWaypointType.DIVERT, - } - - return FlightWaypointJs( - name=waypoint.name, - position=LeafletPoint.from_pydcs(waypoint.position), - altitude_ft=waypoint.alt.feet, - altitude_reference=waypoint.alt_type, - is_movable=is_movable, - should_mark=should_mark, - include_in_path=include_in_path, - timing=timing_info(flight, waypoint_idx), - ) diff --git a/game/server/waypoints/routes.py b/game/server/waypoints/routes.py deleted file mode 100644 index a50d2e057..000000000 --- a/game/server/waypoints/routes.py +++ /dev/null @@ -1,68 +0,0 @@ -from uuid import UUID - -from dcs.mapping import LatLng, Point -from fastapi import APIRouter, Depends, HTTPException, status -from starlette.responses import Response - -from game import Game -from game.ato import Flight -from game.server import GameContext -from game.server.leaflet import LeafletPoint -from game.server.waypoints.models import FlightWaypointJs -from game.sim import GameUpdateEvents - -router: APIRouter = APIRouter(prefix="/waypoints") - - -def waypoints_for_flight(flight: Flight) -> list[FlightWaypointJs]: - return [ - FlightWaypointJs.for_waypoint(w, flight, i) - for i, w in enumerate(flight.flight_plan.waypoints, 1) - ] - - -@router.get( - "/{flight_id}", - operation_id="list_all_waypoints_for_flight", - response_model=list[FlightWaypointJs], -) -def all_waypoints_for_flight( - flight_id: UUID, game: Game = Depends(GameContext.require) -) -> list[FlightWaypointJs]: - return waypoints_for_flight(game.db.flights.get(flight_id)) - - -@router.post( - "/{flight_id}/{waypoint_idx}/position", - operation_id="set_waypoint_position", - status_code=status.HTTP_204_NO_CONTENT, - response_class=Response, -) -def set_position( - flight_id: UUID, - waypoint_idx: int, - position: LeafletPoint, - game: Game = Depends(GameContext.require), -) -> None: - from game.server import EventStream - - flight = game.db.flights.get(flight_id) - if waypoint_idx == 0: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN) - - waypoint = flight.flight_plan.waypoints[waypoint_idx] - waypoint.position = Point.from_latlng( - LatLng(position.lat, position.lng), game.theater.terrain - ) - package_model = ( - GameContext.get_model() - .ato_model_for(flight.blue) - .find_matching_package_model(flight.package) - ) - if package_model is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Could not find PackageModel owning {flight}", - ) - package_model.update_tot() - EventStream.put_nowait(GameUpdateEvents().update_flight(flight)) diff --git a/game/settings/__init__.py b/game/settings/__init__.py deleted file mode 100644 index 5fffc6d30..000000000 --- a/game/settings/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .booleanoption import BooleanOption -from .boundedfloatoption import BoundedFloatOption -from .boundedintoption import BoundedIntOption -from .choicesoption import ChoicesOption -from .minutesoption import MinutesOption -from .optiondescription import OptionDescription -from .settings import AutoAtoBehavior, Settings diff --git a/game/settings/booleanoption.py b/game/settings/booleanoption.py deleted file mode 100644 index 4471b6630..000000000 --- a/game/settings/booleanoption.py +++ /dev/null @@ -1,39 +0,0 @@ -from dataclasses import dataclass, field -from typing import Any, Optional - -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY - - -@dataclass(frozen=True) -class BooleanOption(OptionDescription): - invert: bool - - -def boolean_option( - text: str, - page: str, - section: str, - default: bool, - invert: bool = False, - detail: Optional[str] = None, - tooltip: Optional[str] = None, - causes_expensive_game_update: bool = False, - remember_player_choice: bool = False, - **kwargs: Any, -) -> bool: - return field( - metadata={ - SETTING_DESCRIPTION_KEY: BooleanOption( - page, - section, - text, - detail, - tooltip, - causes_expensive_game_update, - remember_player_choice, - invert, - ) - }, - default=default, - **kwargs, - ) diff --git a/game/settings/boundedfloatoption.py b/game/settings/boundedfloatoption.py deleted file mode 100644 index a47c4d2de..000000000 --- a/game/settings/boundedfloatoption.py +++ /dev/null @@ -1,44 +0,0 @@ -from dataclasses import dataclass, field -from typing import Any, Optional - -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY - - -@dataclass(frozen=True) -class BoundedFloatOption(OptionDescription): - min: float - max: float - divisor: int - - -def bounded_float_option( - text: str, - page: str, - section: str, - default: float, - min: float, - max: float, - divisor: int, - detail: Optional[str] = None, - tooltip: Optional[str] = None, - remember_player_choice: bool = False, - **kwargs: Any, -) -> float: - return field( - metadata={ - SETTING_DESCRIPTION_KEY: BoundedFloatOption( - page, - section, - text, - detail, - tooltip, - causes_expensive_game_update=False, - remember_player_choice=remember_player_choice, - min=min, - max=max, - divisor=divisor, - ) - }, - default=default, - **kwargs, - ) diff --git a/game/settings/boundedintoption.py b/game/settings/boundedintoption.py deleted file mode 100644 index d8de49fad..000000000 --- a/game/settings/boundedintoption.py +++ /dev/null @@ -1,42 +0,0 @@ -from dataclasses import dataclass, field -from typing import Any, Optional - -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY - - -@dataclass(frozen=True) -class BoundedIntOption(OptionDescription): - min: int - max: int - - -def bounded_int_option( - text: str, - page: str, - section: str, - default: int, - min: int, - max: int, - detail: Optional[str] = None, - tooltip: Optional[str] = None, - causes_expensive_game_update: bool = False, - remember_player_choice: bool = False, - **kwargs: Any, -) -> int: - return field( - metadata={ - SETTING_DESCRIPTION_KEY: BoundedIntOption( - page, - section, - text, - detail, - tooltip, - causes_expensive_game_update, - remember_player_choice, - min=min, - max=max, - ) - }, - default=default, - **kwargs, - ) diff --git a/game/settings/choicesoption.py b/game/settings/choicesoption.py deleted file mode 100644 index 4b97b04a2..000000000 --- a/game/settings/choicesoption.py +++ /dev/null @@ -1,49 +0,0 @@ -from dataclasses import dataclass, field -from typing import Any, Generic, Iterable, Mapping, Optional, TypeVar, Union - -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY - -ValueT = TypeVar("ValueT") - - -@dataclass(frozen=True) -class ChoicesOption(OptionDescription, Generic[ValueT]): - choices: dict[str, ValueT] - - def text_for_value(self, value: ValueT) -> str: - for text, _value in self.choices.items(): - if value == _value: - return text - raise ValueError(f"{self} does not contain {value}") - - -def choices_option( - text: str, - page: str, - section: str, - default: ValueT, - choices: Union[Iterable[str], Mapping[str, ValueT]], - detail: Optional[str] = None, - tooltip: Optional[str] = None, - **kwargs: Any, -) -> ValueT: - if not isinstance(choices, Mapping): - choices = {c: c for c in choices} - return field( - metadata={ - SETTING_DESCRIPTION_KEY: ChoicesOption( - page, - section, - text, - detail, - tooltip, - causes_expensive_game_update=False, - # Same as minutes_option, this requires custom serialization before we - # can do this. - remember_player_choice=False, - choices=dict(choices), - ) - }, - default=default, - **kwargs, - ) diff --git a/game/settings/minutesoption.py b/game/settings/minutesoption.py deleted file mode 100644 index 5da5f6c72..000000000 --- a/game/settings/minutesoption.py +++ /dev/null @@ -1,45 +0,0 @@ -from dataclasses import dataclass, field -from datetime import timedelta -from typing import Any, Optional - -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY - - -@dataclass(frozen=True) -class MinutesOption(OptionDescription): - min: int - max: int - - -def minutes_option( - text: str, - page: str, - section: str, - default: timedelta, - min: int, - max: int, - detail: Optional[str] = None, - tooltip: Optional[str] = None, - **kwargs: Any, -) -> timedelta: - return field( - metadata={ - SETTING_DESCRIPTION_KEY: MinutesOption( - page, - section, - text, - detail, - tooltip, - causes_expensive_game_update=False, - # Can't preserve timedelta until we create some custom serialization for - # it. The default serialization is as a python object, which isn't - # allowed in yaml.safe_load because a malicious modification of the - # settings file would be able to execute arbitrary code. - remember_player_choice=False, - min=min, - max=max, - ) - }, - default=default, - **kwargs, - ) diff --git a/game/settings/optiondescription.py b/game/settings/optiondescription.py deleted file mode 100644 index 4db0cdf0c..000000000 --- a/game/settings/optiondescription.py +++ /dev/null @@ -1,22 +0,0 @@ -from dataclasses import dataclass -from typing import Optional - - -SETTING_DESCRIPTION_KEY = "DCS_LIBERATION_SETTING_DESCRIPTION_KEY" - - -@dataclass(frozen=True) -class OptionDescription: - page: str - section: str - text: str - detail: Optional[str] - tooltip: Optional[str] - causes_expensive_game_update: bool - - # If True, the player's selection for this value will be saved to settings.yaml in - # the Liberation user directory when a new game is created, and those values will be - # used by default for new games. This is conditional because many settings are not - # appropriate for cross-game persistence (economy settings are, for example, usually - # hinted by the campaign itself). - remember_player_choice: bool diff --git a/game/settings/settings.py b/game/settings/settings.py deleted file mode 100644 index 8f7409338..000000000 --- a/game/settings/settings.py +++ /dev/null @@ -1,670 +0,0 @@ -import logging -from collections.abc import Iterator -from dataclasses import Field, dataclass, fields -from datetime import timedelta -from enum import Enum, unique -from pathlib import Path -from typing import Any, Optional, get_type_hints - -import yaml -from dcs.forcedoptions import ForcedOptions - -from .booleanoption import boolean_option -from .boundedfloatoption import bounded_float_option -from .boundedintoption import bounded_int_option -from .choicesoption import choices_option -from .minutesoption import minutes_option -from .optiondescription import OptionDescription, SETTING_DESCRIPTION_KEY -from .skilloption import skill_option -from ..ato.starttype import StartType -from ..persistence.paths import liberation_user_dir - - -@unique -class AutoAtoBehavior(Enum): - Disabled = "Disabled" - Never = "Never assign player pilots" - Default = "No preference" - Prefer = "Prefer player pilots" - - -DIFFICULTY_PAGE = "Difficulty" - -AI_DIFFICULTY_SECTION = "AI Difficulty" -MISSION_DIFFICULTY_SECTION = "Mission Difficulty" -MISSION_RESTRICTIONS_SECTION = "Mission Restrictions" - -CAMPAIGN_MANAGEMENT_PAGE = "Campaign Management" - -GENERAL_SECTION = "General" -PILOTS_AND_SQUADRONS_SECTION = "Pilots and Squadrons" -HQ_AUTOMATION_SECTION = "HQ Automation" - -MISSION_GENERATOR_PAGE = "Mission Generator" - -COMMANDERS_SECTION = "Battlefield Commanders" - -GAMEPLAY_SECTION = "Gameplay" - -# TODO: Make sections a type and add headers. -# This section had the header: "Disabling settings below may improve performance, but -# will impact the overall quality of the experience." -PERFORMANCE_SECTION = "Performance" - - -@dataclass -class Settings: - version: Optional[str] = None - - # Difficulty settings - # AI Difficulty - player_skill: str = skill_option( - "Player coalition skill", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - default="Good", - ) - enemy_skill: str = skill_option( - "Enemy coalition skill", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - default="Average", - ) - enemy_vehicle_skill: str = skill_option( - "Enemy AA and vehicles skill", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - default="Average", - ) - player_income_multiplier: float = bounded_float_option( - "Player income multiplier", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - min=0, - max=5, - divisor=10, - default=1.0, - ) - enemy_income_multiplier: float = bounded_float_option( - "Enemy income multiplier", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - min=0, - max=5, - divisor=10, - default=1.0, - ) - invulnerable_player_pilots: bool = boolean_option( - "Player pilots cannot be killed", - page=DIFFICULTY_PAGE, - section=AI_DIFFICULTY_SECTION, - detail=( - "Aircraft are vulnerable, but the player's pilot will be returned to the " - "squadron at the end of the mission" - ), - default=True, - ) - # Mission Difficulty - manpads: bool = boolean_option( - "Manpads on frontlines", - page=DIFFICULTY_PAGE, - section=MISSION_DIFFICULTY_SECTION, - default=True, - ) - night_disabled: bool = boolean_option( - "No night missions", - page=DIFFICULTY_PAGE, - section=MISSION_DIFFICULTY_SECTION, - default=False, - ) - # Mission Restrictions - labels: str = choices_option( - "In game labels", - page=DIFFICULTY_PAGE, - section=MISSION_RESTRICTIONS_SECTION, - choices=["Full", "Abbreviated", "Dot Only", "Neutral Dot", "Off"], - default="Full", - ) - map_coalition_visibility: ForcedOptions.Views = choices_option( - "Map visibility options", - page=DIFFICULTY_PAGE, - section=MISSION_RESTRICTIONS_SECTION, - choices={ - "All": ForcedOptions.Views.All, - "Fog of war": ForcedOptions.Views.Allies, - "Allies only": ForcedOptions.Views.OnlyAllies, - "Own aircraft only": ForcedOptions.Views.MyAircraft, - "Map only": ForcedOptions.Views.OnlyMap, - }, - default=ForcedOptions.Views.All, - ) - external_views_allowed: bool = boolean_option( - "Allow external views", - DIFFICULTY_PAGE, - MISSION_RESTRICTIONS_SECTION, - default=True, - ) - - easy_communication: Optional[bool] = choices_option( - "Easy Communication", - page=DIFFICULTY_PAGE, - section=MISSION_RESTRICTIONS_SECTION, - choices={"Player preference": None, "Enforced on": True, "Enforced off": False}, - default=None, - ) - - battle_damage_assessment: Optional[bool] = choices_option( - "Battle damage assessment", - page=DIFFICULTY_PAGE, - section=MISSION_RESTRICTIONS_SECTION, - choices={"Player preference": None, "Enforced on": True, "Enforced off": False}, - default=None, - ) - - # Campaign management - # General - restrict_weapons_by_date: bool = boolean_option( - "Restrict weapons by date (WIP)", - page=CAMPAIGN_MANAGEMENT_PAGE, - section=GENERAL_SECTION, - default=False, - detail=( - "Restricts weapon availability based on the campaign date. Data is " - "extremely incomplete so does not affect all weapons." - ), - ) - disable_legacy_aewc: bool = boolean_option( - "Spawn invulnerable, always-available AEW&C aircraft (deprecated)", - page=CAMPAIGN_MANAGEMENT_PAGE, - section=GENERAL_SECTION, - default=True, - invert=True, - detail=( - "If checked, an invulnerable friendly AEW&C aircraft that begins the " - "mission on station will be be spawned. This behavior will be removed in a " - "future release." - ), - ) - disable_legacy_tanker: bool = boolean_option( - "Spawn invulnerable, always-available tanker aircraft (deprecated)", - page=CAMPAIGN_MANAGEMENT_PAGE, - section=GENERAL_SECTION, - default=True, - invert=True, - detail=( - "If checked, an invulnerable friendly tanker aircraft that begins the " - "mission on station will be be spawned. This behavior will be removed in a " - "future release." - ), - ) - # Pilots and Squadrons - ai_pilot_levelling: bool = boolean_option( - "Allow AI pilot leveling", - CAMPAIGN_MANAGEMENT_PAGE, - PILOTS_AND_SQUADRONS_SECTION, - default=True, - detail=( - "Set whether or not AI pilots will level up after completing a number of" - " sorties. Since pilot level affects the AI skill, you may wish to disable" - " this, lest you face an Ace!" - ), - ) - #: Feature flag for squadron limits. - enable_squadron_pilot_limits: bool = boolean_option( - "Enable per-squadron pilot limits (WIP)", - CAMPAIGN_MANAGEMENT_PAGE, - PILOTS_AND_SQUADRONS_SECTION, - default=False, - detail=( - "If set, squadrons will be limited to a maximum number of pilots and dead " - "pilots will replenish at a fixed rate, each defined with the settings" - "below. Auto-purchase may buy aircraft for which there are no pilots" - "available, so this feature is still a work-in-progress." - ), - ) - #: The maximum number of pilots a squadron can have at one time. Changing this after - #: the campaign has started will have no immediate effect; pilots already in the - #: squadron will not be removed if the limit is lowered and pilots will not be - #: immediately created if the limit is raised. - squadron_pilot_limit: int = bounded_int_option( - "Maximum number of pilots per squadron", - CAMPAIGN_MANAGEMENT_PAGE, - PILOTS_AND_SQUADRONS_SECTION, - default=12, - min=12, - max=72, - detail=( - "Sets the maximum number of pilots a squadron may have active. " - "Changing this value will not have an immediate effect, but will alter " - "replenishment for future turns." - ), - ) - #: The number of pilots a squadron can replace per turn. - squadron_replenishment_rate: int = bounded_int_option( - "Squadron pilot replenishment rate", - CAMPAIGN_MANAGEMENT_PAGE, - PILOTS_AND_SQUADRONS_SECTION, - default=4, - min=1, - max=20, - detail=( - "Sets the maximum number of pilots that will be recruited to each squadron " - "at the end of each turn. Squadrons will not recruit new pilots beyond the " - "pilot limit, but each squadron with room for more pilots will recruit " - "this many pilots each turn up to the limit." - ), - ) - - # HQ Automation - automate_runway_repair: bool = boolean_option( - "Automate runway repairs", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=False, - remember_player_choice=True, - ) - automate_front_line_reinforcements: bool = boolean_option( - "Automate front-line purchases", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=False, - remember_player_choice=True, - ) - automate_aircraft_reinforcements: bool = boolean_option( - "Automate aircraft purchases", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=False, - remember_player_choice=True, - ) - auto_ato_behavior: AutoAtoBehavior = choices_option( - "Automatic package planning behavior", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=AutoAtoBehavior.Default, - choices={v.value: v for v in AutoAtoBehavior}, - detail=( - "Aircraft auto-purchase is directed by the auto-planner, so disabling " - "auto-planning disables auto-purchase." - ), - ) - auto_ato_player_missions_asap: bool = boolean_option( - "Automatically generated packages with players are scheduled ASAP", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=True, - ) - automate_front_line_stance: bool = boolean_option( - "Automatically manage front line stances", - CAMPAIGN_MANAGEMENT_PAGE, - HQ_AUTOMATION_SECTION, - default=True, - ) - reserves_procurement_target: int = 10 - - # Mission Generator - - # Commanders - game_master_slots: int = bounded_int_option( - "Game master", - page=MISSION_GENERATOR_PAGE, - section=COMMANDERS_SECTION, - default=0, - min=0, - max=100, - ) - tactical_commander_slots: int = bounded_int_option( - "Tactical commander", - page=MISSION_GENERATOR_PAGE, - section=COMMANDERS_SECTION, - default=1, - min=0, - max=100, - ) - jtac_operator_slots: int = bounded_int_option( - "JTAC/Operator", - page=MISSION_GENERATOR_PAGE, - section=COMMANDERS_SECTION, - default=0, - min=0, - max=100, - ) - observer_slots: int = bounded_int_option( - "Observer", - page=MISSION_GENERATOR_PAGE, - section=COMMANDERS_SECTION, - default=1, - min=0, - max=100, - ) - - # Gameplay - ai_has_unlimited_fuel: bool = boolean_option( - "Unlimited fuel for AI flights", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=True, - detail=( - "If enabled, AI-only flights will have unlimited fuel. This can be " - "disabled to force AI flights to play by the same rules as players, but be " - "warned that the DCS AI is not particularly fuel conscious, so will often " - "run out of fuel when players would not." - ), - ) - fast_forward_to_first_contact: bool = boolean_option( - "Fast forward mission to first contact (WIP)", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=False, - detail=( - "If enabled, the mission will be generated at the point of first contact. " - "If you enable this option, you will not be able to create new flights " - 'after pressing "TAKE OFF". Doing so will create an error the next time ' - 'you press "TAKE OFF". Save your game first if you want to make ' - "modifications." - ), - ) - reload_pre_sim_checkpoint_on_abort: bool = boolean_option( - "Reset mission to pre-take off conditions on abort", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=True, - detail=( - "If enabled, the game will automatically reload a pre-take off save when " - "aborting take off. If this is disabled, you will need to manually re-load " - "your game after aborting take off." - ), - ) - player_mission_interrupts_sim_at: Optional[StartType] = choices_option( - "Player missions interrupt fast forward", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=None, - choices={ - "Never": None, - "At startup time": StartType.COLD, - "At taxi time": StartType.WARM, - "At takeoff time": StartType.RUNWAY, - }, - detail=( - "Determines what player mission states will interrupt fast-forwarding to " - "first contact, if enabled. If never is selected player missions will not " - "impact simulation and player missions may be generated mid-flight. The " - "other options will cause the mission to be generated as soon as a player " - "mission reaches the set state or at first contact, whichever comes first." - ), - ) - auto_resolve_combat: bool = boolean_option( - "Auto-resolve combat during fast-forward (WIP)", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=False, - detail=( - 'Requires a "Player missions interrupt fast forward" setting other than ' - '"Never" If enabled, aircraft entering combat during fast forward will have' - "their combat auto-resolved after a period of time. This allows the " - "simulation to advance further into the mission before requiring mission " - "generation, but simulation is currently very rudimentary so may result in " - "huge losses." - ), - ) - supercarrier: bool = boolean_option( - "Use supercarrier module", - MISSION_GENERATOR_PAGE, - GAMEPLAY_SECTION, - default=False, - remember_player_choice=True, - ) - generate_marks: bool = boolean_option( - "Put objective markers on the map", - MISSION_GENERATOR_PAGE, - GAMEPLAY_SECTION, - default=True, - ) - generate_dark_kneeboard: bool = boolean_option( - "Generate dark kneeboard", - MISSION_GENERATOR_PAGE, - GAMEPLAY_SECTION, - default=False, - detail=( - "Dark kneeboard for night missions. This will likely make the kneeboard on " - "the pilot leg unreadable." - ), - ) - never_delay_player_flights: bool = boolean_option( - "Player flights ignore TOT and spawn immediately", - MISSION_GENERATOR_PAGE, - GAMEPLAY_SECTION, - default=False, - detail=( - "Does not adjust package waypoint times. Should not be used if players " - "have runway or in-air starts." - ), - tooltip=( - "Always spawns player aircraft immediately, even if their start time is " - "more than 10 minutes after the start of the mission. This does " - "not alter the timing of your mission. Your TOT will not change. This " - "option only allows the player to wait on the ground." - ), - ) - default_start_type: StartType = choices_option( - "Default start type for AI aircraft", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - choices={v.value: v for v in StartType}, - default=StartType.COLD, - detail=( - "Warning: Options other than Cold will significantly reduce the number of " - "targets available for OCA/Aircraft missions, and OCA/Aircraft flights " - "will not be included in automatically planned OCA packages." - ), - ) - # Mission specific - desired_player_mission_duration: timedelta = minutes_option( - "Desired mission duration", - page=MISSION_GENERATOR_PAGE, - section=GAMEPLAY_SECTION, - default=timedelta(minutes=60), - min=30, - max=150, - ) - - # Performance - perf_smoke_gen: bool = boolean_option( - "Smoke visual effect on the front line", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - perf_smoke_spacing: int = bounded_int_option( - "Smoke generator spacing (higher means less smoke)", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=1600, - min=800, - max=24000, - ) - perf_red_alert_state: bool = boolean_option( - "SAM starts in red alert mode", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - perf_artillery: bool = boolean_option( - "Artillery strikes", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - generate_fire_tasks_for_missile_sites: bool = boolean_option( - "Generate fire tasks for missile sites", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - detail=( - "If enabled, missile sites like V2s and Scuds will fire on random targets " - "at the start of the mission." - ), - default=True, - ) - perf_moving_units: bool = boolean_option( - "Moving ground units", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - convoys_travel_full_distance: bool = boolean_option( - "Convoys drive the full distance between control points", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - perf_infantry: bool = boolean_option( - "Generate infantry squads alongside vehicles", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - perf_destroyed_units: bool = boolean_option( - "Generate carcasses for units destroyed in previous turns", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - # Performance culling - perf_culling: bool = boolean_option( - "Culling of distant units enabled", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=False, - ) - perf_culling_distance: int = bounded_int_option( - "Culling distance (km)", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=100, - min=10, - max=10000, - causes_expensive_game_update=True, - ) - perf_do_not_cull_threatening_iads: bool = boolean_option( - "Do not cull threatening IADS", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - ) - perf_do_not_cull_carrier: bool = boolean_option( - "Do not cull carrier's surroundings", - page=MISSION_GENERATOR_PAGE, - section=PERFORMANCE_SECTION, - default=True, - causes_expensive_game_update=True, - ) - - # Cheating. Not using auto settings because the same page also has buttons which do - # not alter settings. - show_red_ato: bool = False - enable_frontline_cheats: bool = False - enable_base_capture_cheat: bool = False - enable_runway_state_cheat: bool = False - - only_player_takeoff: bool = True # Legacy parameter do not use - - def save_player_settings(self) -> None: - """Saves the player's global settings to the user directory.""" - settings: dict[str, Any] = {} - for name, description in self.all_fields(): - if description.remember_player_choice: - settings[name] = self.__dict__[name] - - with self._player_settings_file.open("w", encoding="utf-8") as settings_file: - yaml.dump(settings, settings_file, sort_keys=False, explicit_start=True) - - def merge_player_settings(self) -> None: - """Updates with the player's global settings.""" - settings_path = self._player_settings_file - if not settings_path.exists(): - return - with settings_path.open(encoding="utf-8") as settings_file: - data = yaml.safe_load(settings_file) - - if data is None: - logging.warning("Saved settings file %s is empty", settings_path) - return - - expected_types = get_type_hints(Settings) - for key, value in data.items(): - if key not in self.__dict__: - logging.warning( - "Unexpected settings key found in %s: %s. Ignoring.", - settings_path, - key, - ) - continue - - expected_type = expected_types[key] - if not isinstance(value, expected_type): - logging.error( - "%s in %s does not have the expected type %s (is %s). Ignoring.", - key, - settings_path, - expected_type.__name__, - value.__class__.__name__, - ) - continue - self.__dict__[key] = value - - @property - def _player_settings_file(self) -> Path: - """Returns the path to the player's global settings file.""" - return liberation_user_dir() / "settings.yaml" - - def __setstate__(self, state: dict[str, Any]) -> None: - # __setstate__ is called with the dict of the object being unpickled. We - # can provide save compatibility for new settings options (which - # normally would not be present in the unpickled object) by creating a - # new settings object, updating it with the unpickled state, and - # updating our dict with that. - new_state = Settings().__dict__ - new_state.update(state) - self.__dict__.update(new_state) - - @classmethod - def _field_description(cls, settings_field: Field[Any]) -> OptionDescription: - return settings_field.metadata[SETTING_DESCRIPTION_KEY] - - @classmethod - def pages(cls) -> Iterator[str]: - seen: set[str] = set() - for settings_field in cls._user_fields(): - description = cls._field_description(settings_field) - if description.page not in seen: - yield description.page - seen.add(description.page) - - @classmethod - def sections(cls, page: str) -> Iterator[str]: - seen: set[str] = set() - for settings_field in cls._user_fields(): - description = cls._field_description(settings_field) - if description.page == page and description.section not in seen: - yield description.section - seen.add(description.section) - - @classmethod - def all_fields(cls) -> Iterator[tuple[str, OptionDescription]]: - for settings_field in cls._user_fields(): - yield settings_field.name, cls._field_description(settings_field) - - @classmethod - def fields_for( - cls, page: str, section: str - ) -> Iterator[tuple[str, OptionDescription]]: - for name, description in cls.all_fields(): - if description.page == page and description.section == section: - yield name, description - - @classmethod - def _user_fields(cls) -> Iterator[Field[Any]]: - for settings_field in fields(cls): - if SETTING_DESCRIPTION_KEY in settings_field.metadata: - yield settings_field diff --git a/game/settings/skilloption.py b/game/settings/skilloption.py deleted file mode 100644 index 4f6b582ea..000000000 --- a/game/settings/skilloption.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Any, Optional - -from .choicesoption import choices_option - - -def skill_option( - text: str, - page: str, - section: str, - default: str, - detail: Optional[str] = None, - tooltip: Optional[str] = None, - **kwargs: Any, -) -> str: - return choices_option( - text, - page, - section, - default, - ["Average", "Good", "High", "Excellent"], - detail=detail, - tooltip=tooltip, - **kwargs, - ) diff --git a/game/sidc.py b/game/sidc.py deleted file mode 100644 index 6fcef1442..000000000 --- a/game/sidc.py +++ /dev/null @@ -1,353 +0,0 @@ -"""Implements Symbol Identification Codes (SIDCs) as defined by NATO APP-6(D). - -This implementation only covers assembly of the identifier strings. The front-end is -responsible for drawing the icons. - -The third ten digits (used for national modifications and additions not covered by -APP-6) are not implemented. The third set of ten digits are optional and will be omitted -from the output. - -https://nso.nato.int/nso/nsdd/main/standards/ap-details/1912/EN -https://www.spatialillusions.com/milsymbol/docs/milsymbol-APP6d.html -""" -from __future__ import annotations - -from abc import ABC, abstractmethod -from dataclasses import dataclass -from enum import IntEnum, unique - -# Version field defined by A.5. -VERSION = 10 - - -@unique -class Context(IntEnum): - """Context field defined by A.6..""" - - REALITY = 0 - EXERCISE = 1 - SIMULATION = 2 - # 3-9 are reserved for future use. - - def __str__(self) -> str: - return str(self.value) - - -@unique -class StandardIdentity(IntEnum): - """Standard identity field defined by A.6.""" - - PENDING = 0 - UNKNOWN = 1 - ASSUMED_FRIEND = 2 - FRIEND = 3 - NEUTRAL = 4 - SUSPECT_JOKER = 5 - HOSTILE_FAKER = 6 - # 7-9 are reserved for future use. - - def __str__(self) -> str: - return str(self.value) - - -@unique -class SymbolSet(IntEnum): - """Symbol set field defined by A.7.""" - - UNKNOWN = 0 - AIR = 1 - AIR_MISSILE = 2 - SPACE = 5 - SPACE_MISSILE = 6 - LAND_UNIT = 10 - LAND_CIVILIAN_UNIT_ORGANIZATION = 11 - LAND_EQUIPMENT = 15 - LAND_INSTALLATIONS = 20 - CONTROL_MEASURE = 25 - DISMOUNTED_INDIVIDUAL = 27 - SEA_SURFACE = 30 - SEA_SUBSURFACE = 35 - MINE_WARFARE = 36 - ACTIVITY_EVENT = 40 - ATMOSPHERIC = 45 - OCEANOGRAPHIC = 46 - METEOROLOGICAL_SPACE = 47 - SIGNALS_INTELLIGENCE_SPACE = 50 - SIGNALS_INTELLIGENCE_AIR = 51 - SIGNALS_INTELLIGENCE_LAND = 52 - SIGNALS_INTELLIGENCE_SURFACE = 53 - SIGNALS_INTELLIGENCE_SUBSURFACE = 54 - CYBERSPACE_SPACE = 60 - CYBERSPACE_AIR = 61 - CYBERSPACE_LAND = 62 - CYBERSPACE_SURFACE = 63 - CYBERSPACE_SUBSURFACE = 64 - VERSION_EXTENSION_FLAG = 99 - # All other values reserved for future use. - - def __str__(self) -> str: - return f"{self.value:02}" - - -@unique -class Status(IntEnum): - """Status field defined by A.8 Status.""" - - PRESENT = 0 - PLANNED_ANTICIPATED_SUSPECT = 1 - PRESENT_FULLY_CAPABLE = 2 - PRESENT_DAMAGED = 3 - PRESENT_DESTROYED = 4 - PRESENT_FULL_TO_CAPACITY = 5 - # 6-8 reserved for future use. - VERSION_EXTENSION_FLAG = 9 - - def __str__(self) -> str: - return str(self.value) - - -@unique -class HeadquartersTaskForceDummy(IntEnum): - """Headquarters/Task Force/Dummy field defined by A.9.""" - - NOT_APPLICABLE = 0 - FEINT_DUMMY = 1 - HEADQUARTERS = 2 - FEINT_DUMMY_HEADQUARTERS = 3 - TASK_FORCE = 4 - FEINT_DUMMY_TASK_FORCE = 5 - TASK_FORCE_HEADQUARTERS = 6 - FEINT_DUMMY_TASK_FORCE_HEADQUARTERS = 7 - # 8 reserved for future use. - VERSION_EXTENSION_FLAG = 9 - - def __str__(self) -> str: - return str(self.value) - - -@unique -class Amplifier(IntEnum): - """Unit Echelon/Equipment Mobility/Naval Towed Array Amplifier defined by A.10""" - - UNKNOWN = 0 - - # Echelon at brigade and below - TEAM_CREW = 11 - SQUAD = 12 - SECTION = 13 - PLATOON_DETACHMENT = 14 - COMPANY_BATTERY_TROOP = 15 - BATTALION_SQUADRON = 16 - REGIMENT_GROUP = 17 - BRIGADE = 18 - VERSION_EXTENSION_FLAG = 19 - - # Echelon at brigade and above - DIVISION = 21 - CORP_MARINE_EXPEDITIONARY_FORCE = 22 - ARMY = 23 - ARMY_GROUP_FRONT = 24 - REGION_THEATRE = 25 - COMMAND = 26 - # 27-28 reserved for future use. - VERSION_EXTENSION_FLAG2 = 29 - - # Equipment mobility on land - WHEELED_LIMITED_CROSS_COUNTRY = 31 - WHEELED_CROSS_COUNTRY = 32 - TRACKED = 33 - WHEELED_AND_TRAKCED_COMBINATION = 34 - TOWED = 35 - RAIL = 36 - PACK_ANIMALS = 37 - # 38 reserved for future use. - VERSION_EXTENSION_FLAG3 = 39 - - # Equipment mobility on snow - OVER_SNOW = 41 - SLED = 42 - # 3-8 reserved for future use. - VERSION_EXTENSION_FLAG4 = 49 - - # Equipment mobility on water - BARGE = 51 - AMPHIBIOUS = 52 - # 3-8 reserved for future use. - VERSION_EXTENSION_FLAG5 = 59 - - # Naval towed array - SHORT_TOWED_ARRAY = 61 - LONG_TOWED_ARRAY = 62 - # 3-8 reserved for future use. - VERSION_EXTENSION_FLAG6 = 69 - - # Leadership indicator - LEADER_INDIVIDUAL = 71 - DEPUTY_INDIVIDUAL = 72 - # 3-8 reserved for future use. - VERSION_EXTENSION_FLAG7 = 79 - - # 80-89 reserved for future use. - # 90-99 version extension flag. - - def __str__(self) -> str: - return f"{self.value:02}" - - -class Entity(IntEnum): - def __str__(self) -> str: - return f"{self.value:06}" - - -# Entity types (the second set of ten digits are implemented as-needed. These are -# defined by section A.13. Entity/Entity Type/Entity Subtype and Sector 1 and Sector 2 -# Modifiers. The specific entity enum used by the SIDC depends on the symbol set used. -@unique -class AirEntity(Entity): - """Air Entity/Entity Type/Entity Subtype defined by table A-10.""" - - UNSPECIFIED = 0 - ATTACK_STRIKE = 110102 - BOMBER = 110103 - FIGHTER = 110104 - FIGHTER_BOMBER = 110105 - CARGO = 110107 - ELECTRONIC_COMBAT_JAMMER = 110108 - TANKER = 110109 - PATROL = 110110 - RECONNAISSANCE = 110111 - UTILITY = 110113 - VSTOL = 110114 - AIRBORNE_EARLY_WARNING = 110116 - ANTISURFACE_WARFARE = 110117 - ANTISUBMARINE_WARFARE = 110118 - COMBAT_SEARCH_AND_RESCUE = 110120 - SUPPRESSION_OF_ENEMY_AIR_DEFENCE = 110130 - ESCORT = 110132 - ELECTRONIC_ATTACK = 110133 - ROTARY_WING = 110200 - - -@unique -class LandUnitEntity(Entity): - """Land Unit Entity/Entity Type/Entity Subtype defined by table A-19.""" - - UNSPECIFIED = 0 - - ARMOR_ARMORED_MECHANIZED_SELF_PROPELLED_TRACKED = 120500 - AIR_DEFENSE = 130100 - MISSILE = 130700 - - -@unique -class LandEquipmentEntity(Entity): - """Land Equipment Entity/Entity Type/Entity Subtype defined by table A-25.""" - - UNSPECIFIED = 0 - - RADAR = 220300 - - -@unique -class LandInstallationEntity(Entity): - """Land Installation Entity/Entity Type/Entity Subtype defined by table A-27.""" - - UNSPECIFIED = 0 - - AMMUNITION_CACHE = 110300 - WAREHOUSE_STORAGE_FACILITY = 112000 - TENTED_CAMP = 111900 - GENERATION_STATION = 120502 - PETROLEUM_FACILITY = 120504 - MILITARY_BASE = 120802 - MILITARY_INFRASTRUCTURE = 120800 - PUBLIC_VENUES_INFRASTRUCTURE = 121000 - TELECOMMUNICATIONS_TOWER = 121203 - AIPORT_AIR_BASE = 121301 - HELICOPTER_LANDING_SITE = 121305 - MAINTENANCE_FACILITY = 121306 - - -@unique -class SeaSurfaceEntity(Entity): - """Sea Surface Entity/Entity Type/Entity Subtype defined by table A-34.""" - - UNSPECIFIED = 0 - - CARRIER = 120100 - SURFACE_COMBATANT_LINE = 120200 - AMPHIBIOUS_ASSAULT_SHIP_GENERAL = 120303 - - -@unique -class UnknownEntity(Entity): - """Fallback entity type used when the symbol set is not known.""" - - UNSPECIFIED = 0 - - -class Modifier(IntEnum): - """Fallback modifier used when the symbol set is not known.""" - - UNSPECIFIED = 0 - - def __str__(self) -> str: - return f"{self.value:02}" - - -@dataclass -class SymbolIdentificationCode: - version = VERSION - context: Context = Context.REALITY - standard_identity: StandardIdentity = StandardIdentity.UNKNOWN - symbol_set: SymbolSet = SymbolSet.UNKNOWN - status: Status = Status.PRESENT - headquarters_task_force_dummy: HeadquartersTaskForceDummy = ( - HeadquartersTaskForceDummy.NOT_APPLICABLE - ) - amplifier: Amplifier = Amplifier.UNKNOWN - entity: Entity = UnknownEntity.UNSPECIFIED - sector_one_modifier = Modifier.UNSPECIFIED - sector_two_modifier = Modifier.UNSPECIFIED - - def __str__(self) -> str: - return "".join( - [ - f"{self.version:02}", - str(self.context), - str(self.standard_identity), - str(self.symbol_set), - str(self.status), - str(self.headquarters_task_force_dummy), - str(self.amplifier), - str(self.entity), - str(self.sector_one_modifier), - str(self.sector_two_modifier), - ] - ) - - -class SidcDescribable(ABC): - @property - @abstractmethod - def standard_identity(self) -> StandardIdentity: - ... - - @property - @abstractmethod - def sidc_status(self) -> Status: - ... - - @property - @abstractmethod - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - ... - - def sidc(self) -> SymbolIdentificationCode: - symbol_set, entity = self.symbol_set_and_entity - return SymbolIdentificationCode( - standard_identity=self.standard_identity, - symbol_set=symbol_set, - status=self.sidc_status, - entity=entity, - ) diff --git a/game/sim/__init__.py b/game/sim/__init__.py deleted file mode 100644 index fbe751029..000000000 --- a/game/sim/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .gameupdateevents import GameUpdateEvents -from .missionsimulation import MissionSimulation diff --git a/game/sim/aircraftsimulation.py b/game/sim/aircraftsimulation.py deleted file mode 100644 index 892641488..000000000 --- a/game/sim/aircraftsimulation.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -from collections.abc import Iterator -from datetime import datetime, timedelta - -from typing_extensions import TYPE_CHECKING - -from game.ato.flightstate import ( - Uninitialized, -) -from .combat import CombatInitiator, FrozenCombat -from .gameupdateevents import GameUpdateEvents -from .simulationresults import SimulationResults - -if TYPE_CHECKING: - from game import Game - from game.ato import Flight - - -class AircraftSimulation: - def __init__(self, game: Game) -> None: - self.game = game - self.combats: list[FrozenCombat] = [] - self.results = SimulationResults() - - def begin_simulation(self) -> None: - self.reset() - self.set_initial_flight_states() - - def on_game_tick( - self, events: GameUpdateEvents, time: datetime, duration: timedelta - ) -> None: - if not self.game.settings.auto_resolve_combat and self.combats: - logging.error( - "Cannot resume simulation because aircraft are in combat and " - "auto-resolve is disabled" - ) - events.complete_simulation() - return - - still_active = [] - for combat in self.combats: - if combat.on_game_tick(time, duration, self.results, events): - events.end_combat(combat) - else: - still_active.append(combat) - self.combats = still_active - - for flight in self.iter_flights(): - flight.on_game_tick(events, time, duration) - - # Finish updating all flights before checking for combat so that the new - # positions are used. - CombatInitiator(self.game, self.combats, events).update_active_combats() - - # After updating all combat states, check for halts. - for flight in self.iter_flights(): - if flight.should_halt_sim(): - events.complete_simulation() - return - - if not self.game.settings.auto_resolve_combat and self.combats: - events.complete_simulation() - - def set_initial_flight_states(self) -> None: - now = self.game.conditions.start_time - for flight in self.iter_flights(): - flight.state.reinitialize(now) - - def reset(self) -> None: - for flight in self.iter_flights(): - flight.set_state(Uninitialized(flight, self.game.settings)) - self.combats = [] - - def iter_flights(self) -> Iterator[Flight]: - packages = itertools.chain( - self.game.blue.ato.packages, self.game.red.ato.packages - ) - for package in packages: - yield from package.flights diff --git a/game/sim/combat/__init__.py b/game/sim/combat/__init__.py deleted file mode 100644 index fab1a1c12..000000000 --- a/game/sim/combat/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .combatinitiator import CombatInitiator -from .frozencombat import FrozenCombat diff --git a/game/sim/combat/aircombat.py b/game/sim/combat/aircombat.py deleted file mode 100644 index 0fc6e948c..000000000 --- a/game/sim/combat/aircombat.py +++ /dev/null @@ -1,104 +0,0 @@ -from __future__ import annotations - -import logging -import random -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from shapely.ops import unary_union - -from game.ato.flightstate import InCombat, InFlight -from game.utils import dcs_to_shapely_point -from .joinablecombat import JoinableCombat -from .. import GameUpdateEvents - -if TYPE_CHECKING: - from game.ato import Flight - from ..simulationresults import SimulationResults - - -class AirCombat(JoinableCombat): - def __init__(self, freeze_duration: timedelta, flights: list[Flight]) -> None: - super().__init__(freeze_duration, flights) - footprints = [] - for flight in self.flights: - if (region := flight.state.a2a_commit_region()) is not None: - footprints.append(region) - self.footprint = unary_union(footprints) - - def joinable_by(self, flight: Flight) -> bool: - if not flight.state.will_join_air_combat: - return False - - if not isinstance(flight.state, InFlight): - raise NotImplementedError( - f"Only InFlight flights are expected to join air combat. {flight} is " - "not InFlight" - ) - - if self.footprint.intersects( - dcs_to_shapely_point(flight.state.estimate_position()) - ): - return True - return False - - def __str__(self) -> str: - blue_flights = [] - red_flights = [] - for flight in self.flights: - if flight.squadron.player: - blue_flights.append(str(flight)) - else: - red_flights.append(str(flight)) - - blue = ", ".join(blue_flights) - red = ", ".join(red_flights) - return f"air combat {blue} vs {red}" - - def because(self) -> str: - return f"of {self}" - - def describe(self) -> str: - return f"in air-to-air combat" - - def resolve( - self, - results: SimulationResults, - events: GameUpdateEvents, - time: datetime, - elapsed_time: timedelta, - ) -> None: - blue = [] - red = [] - for flight in self.flights: - if flight.squadron.player: - blue.append(flight) - else: - red.append(flight) - if len(blue) > len(red): - winner = blue - loser = red - elif len(blue) < len(red): - winner = red - loser = blue - elif random.random() >= 0.5: - winner = blue - loser = red - else: - winner = red - loser = blue - - if winner == blue: - logging.debug(f"{self} auto-resolved as blue victory") - else: - logging.debug(f"{self} auto-resolved as red victory") - - for flight in loser: - flight.kill(results, events) - - for flight in winner: - assert isinstance(flight.state, InCombat) - if random.random() >= 0.5: - flight.kill(results, events) - else: - flight.state.exit_combat(events, time, elapsed_time) diff --git a/game/sim/combat/aircraftengagementzones.py b/game/sim/combat/aircraftengagementzones.py deleted file mode 100644 index b98ddaa5d..000000000 --- a/game/sim/combat/aircraftengagementzones.py +++ /dev/null @@ -1,66 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from typing import Optional, TYPE_CHECKING - -from dcs import Point -from shapely.ops import unary_union - -from game.utils import dcs_to_shapely_point - -if TYPE_CHECKING: - from game.ato import Flight - from game.ato.airtaaskingorder import AirTaskingOrder - from game.threatzones import ThreatPoly - from game.sim.combat import FrozenCombat - - -class AircraftEngagementZones: - def __init__(self, individual_zones: dict[Flight, ThreatPoly]) -> None: - self.individual_zones = individual_zones - self.threat_zones = self._make_combined_zone() - - def update_for_combat(self, combat: FrozenCombat) -> None: - for flight in combat.iter_flights(): - try: - del self.individual_zones[flight] - except KeyError: - pass - self.threat_zones = self._make_combined_zone() - - def remove_flight(self, flight: Flight) -> None: - try: - del self.individual_zones[flight] - except KeyError: - pass - self.threat_zones = self._make_combined_zone() - - def _make_combined_zone(self) -> ThreatPoly: - zones = [] - for zone in self.individual_zones.values(): - try: - zones.extend(zone.geoms) - except AttributeError: - zones.append(zone) - return unary_union(zones) - - def covers(self, position: Point) -> bool: - return self.threat_zones.intersects(dcs_to_shapely_point(position)) - - def iter_intercepting_flights(self, position: Point) -> Iterator[Flight]: - for flight, zone in self.individual_zones.items(): - if zone.intersects(dcs_to_shapely_point(position)): - yield flight - - @classmethod - def from_ato(cls, ato: AirTaskingOrder) -> AircraftEngagementZones: - zones = {} - for package in ato.packages: - for flight in package.flights: - if (region := cls.commit_region(flight)) is not None: - zones[flight] = region - return AircraftEngagementZones(zones) - - @classmethod - def commit_region(cls, flight: Flight) -> Optional[ThreatPoly]: - return flight.state.a2a_commit_region() diff --git a/game/sim/combat/atip.py b/game/sim/combat/atip.py deleted file mode 100644 index 61ed55b5e..000000000 --- a/game/sim/combat/atip.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import logging -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from .frozencombat import FrozenCombat -from .. import GameUpdateEvents -from ...ato.flightstate import InCombat - -if TYPE_CHECKING: - from game.ato import Flight - from ..simulationresults import SimulationResults - - -class AtIp(FrozenCombat): - def __init__(self, freeze_duration: timedelta, flight: Flight) -> None: - super().__init__(freeze_duration) - self.flight = flight - - def because(self) -> str: - return f"{self.flight} is at its IP" - - def describe(self) -> str: - return f"at IP" - - def iter_flights(self) -> Iterator[Flight]: - yield self.flight - - def resolve( - self, - results: SimulationResults, - events: GameUpdateEvents, - time: datetime, - elapsed_time: timedelta, - ) -> None: - logging.debug( - f"{self.flight} attack on {self.flight.package.target} auto-resolved with " - "mission failure but no losses" - ) - assert isinstance(self.flight.state, InCombat) - self.flight.state.exit_combat( - events, time, elapsed_time, avoid_further_combat=True - ) diff --git a/game/sim/combat/combatinitiator.py b/game/sim/combat/combatinitiator.py deleted file mode 100644 index c5d064d9f..000000000 --- a/game/sim/combat/combatinitiator.py +++ /dev/null @@ -1,120 +0,0 @@ -from __future__ import annotations - -import itertools -import logging -from collections.abc import Iterator -from datetime import timedelta -from typing import Optional, TYPE_CHECKING - -from .aircombat import AirCombat -from .aircraftengagementzones import AircraftEngagementZones -from .atip import AtIp -from .defendingsam import DefendingSam -from .joinablecombat import JoinableCombat -from .samengagementzones import SamEngagementZones -from ..gameupdateevents import GameUpdateEvents - -if TYPE_CHECKING: - from game import Game - from game.ato import Flight - from .frozencombat import FrozenCombat - - -class CombatInitiator: - def __init__( - self, game: Game, combats: list[FrozenCombat], events: GameUpdateEvents - ) -> None: - self.game = game - self.combats = combats - self.events = events - - def update_active_combats(self) -> None: - blue_a2a = AircraftEngagementZones.from_ato(self.game.blue.ato) - red_a2a = AircraftEngagementZones.from_ato(self.game.red.ato) - blue_sam = SamEngagementZones.from_theater(self.game.theater, player=True) - red_sam = SamEngagementZones.from_theater(self.game.theater, player=False) - - # Check each vulnerable flight to see if it has initiated combat. If any flight - # initiates combat, a single FrozenCombat will be created for all involved - # flights and the FlightState of each flight will be updated accordingly. - # - # There's some nuance to this behavior. Duplicate combats are avoided because - # InCombat flight states are not considered vulnerable. That means that once an - # aircraft has entered combat it will not be rechecked later in the loop or on - # another tick. - for flight in self.iter_flights(): - if flight.state.in_combat: - return - - if flight.squadron.player: - a2a = red_a2a - own_a2a = blue_a2a - sam = red_sam - else: - a2a = blue_a2a - own_a2a = red_a2a - sam = blue_sam - self.check_flight_for_combat(flight, a2a, own_a2a, sam) - - def check_flight_for_combat( - self, - flight: Flight, - a2a: AircraftEngagementZones, - own_a2a: AircraftEngagementZones, - sam: SamEngagementZones, - ) -> None: - if (joined := self.check_flight_for_joined_combat(flight)) is not None: - logging.info(f"{flight} is joining existing combat {joined}") - joined.join(flight) - own_a2a.remove_flight(flight) - self.events.update_combat(joined) - elif (combat := self.check_flight_for_new_combat(flight, a2a, sam)) is not None: - logging.info(f"Creating new combat because {combat.because()}") - combat.update_flight_states() - # Remove any preoccupied flights from the list of potential air-to-air - # threats. This prevents BARCAPs (and other air-to-air types) from getting - # involved in multiple combats simultaneously. Additional air-to-air - # aircraft may join existing combats, but they will not create new combats. - a2a.update_for_combat(combat) - own_a2a.update_for_combat(combat) - self.combats.append(combat) - self.events.new_combat(combat) - - def check_flight_for_joined_combat( - self, flight: Flight - ) -> Optional[JoinableCombat]: - for combat in self.combats: - if isinstance(combat, JoinableCombat) and combat.joinable_by(flight): - return combat - return None - - @staticmethod - def check_flight_for_new_combat( - flight: Flight, a2a: AircraftEngagementZones, sam: SamEngagementZones - ) -> Optional[FrozenCombat]: - if not flight.state.in_flight: - return None - - if flight.state.is_at_ip and not flight.state.avoid_further_combat: - return AtIp(timedelta(minutes=1), flight) - - position = flight.state.estimate_position() - - if flight.state.vulnerable_to_intercept and a2a.covers(position): - flights = [flight] - flights.extend(a2a.iter_intercepting_flights(position)) - return AirCombat(timedelta(minutes=1), flights) - - if flight.state.vulnerable_to_sam and sam.covers(position): - return DefendingSam( - timedelta(minutes=1), flight, list(sam.iter_threatening_sams(position)) - ) - - return None - - def iter_flights(self) -> Iterator[Flight]: - packages = itertools.chain( - self.game.blue.ato.packages, self.game.red.ato.packages - ) - for package in packages: - yield from package.flights diff --git a/game/sim/combat/defendingsam.py b/game/sim/combat/defendingsam.py deleted file mode 100644 index 2dfe98fb1..000000000 --- a/game/sim/combat/defendingsam.py +++ /dev/null @@ -1,55 +0,0 @@ -from __future__ import annotations - -import logging -import random -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from game.ato.flightstate import InCombat -from .frozencombat import FrozenCombat -from .. import GameUpdateEvents - -if TYPE_CHECKING: - from game.ato import Flight - from game.theater import TheaterGroundObject - from ..simulationresults import SimulationResults - - -class DefendingSam(FrozenCombat): - def __init__( - self, - freeze_duration: timedelta, - flight: Flight, - air_defenses: list[TheaterGroundObject], - ) -> None: - super().__init__(freeze_duration) - self.flight = flight - self.air_defenses = air_defenses - - def because(self) -> str: - sams = ", ".join(str(d) for d in self.air_defenses) - return f"{self.flight} is engaged by enemy air defenses: {sams}" - - def describe(self) -> str: - return f"engaged by enemy air defenses" - - def iter_flights(self) -> Iterator[Flight]: - yield self.flight - - def resolve( - self, - results: SimulationResults, - events: GameUpdateEvents, - time: datetime, - elapsed_time: timedelta, - ) -> None: - assert isinstance(self.flight.state, InCombat) - if random.random() >= 0.5: - logging.debug(f"Air defense combat auto-resolved with {self.flight} lost") - self.flight.kill(results, events) - else: - logging.debug( - f"Air defense combat auto-resolved with {self.flight} surviving" - ) - self.flight.state.exit_combat(events, time, elapsed_time) diff --git a/game/sim/combat/frozencombat.py b/game/sim/combat/frozencombat.py deleted file mode 100644 index 332c107f2..000000000 --- a/game/sim/combat/frozencombat.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -import uuid -from abc import ABC, abstractmethod -from collections.abc import Iterator -from datetime import datetime, timedelta -from typing import TYPE_CHECKING - -from game.ato.flightstate import InCombat, InFlight -from .. import GameUpdateEvents - -if TYPE_CHECKING: - from game.ato import Flight - from ..simulationresults import SimulationResults - - -class FrozenCombat(ABC): - def __init__(self, freeze_duration: timedelta) -> None: - self.id = uuid.uuid4() - self.freeze_duration = freeze_duration - self.elapsed_time = timedelta() - - def on_game_tick( - self, - time: datetime, - duration: timedelta, - results: SimulationResults, - events: GameUpdateEvents, - ) -> bool: - self.elapsed_time += duration - if self.elapsed_time >= self.freeze_duration: - self.resolve(results, events, time, self.elapsed_time) - return True - return False - - @abstractmethod - def resolve( - self, - results: SimulationResults, - events: GameUpdateEvents, - time: datetime, - elapsed_time: timedelta, - ) -> None: - ... - - @abstractmethod - def because(self) -> str: - ... - - @abstractmethod - def describe(self) -> str: - ... - - @abstractmethod - def iter_flights(self) -> Iterator[Flight]: - ... - - def update_flight_states(self) -> None: - for flight in self.iter_flights(): - if not isinstance(flight.state, InFlight): - raise RuntimeError( - f"Found non in-flight aircraft engaged in combat: {flight}" - ) - flight.set_state(InCombat(flight.state, self)) diff --git a/game/sim/combat/joinablecombat.py b/game/sim/combat/joinablecombat.py deleted file mode 100644 index 84c19c40d..000000000 --- a/game/sim/combat/joinablecombat.py +++ /dev/null @@ -1,31 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections.abc import Iterator -from datetime import timedelta -from typing import TYPE_CHECKING - -from game.ato.flightstate import InCombat, InFlight -from .frozencombat import FrozenCombat - -if TYPE_CHECKING: - from game.ato import Flight - - -class JoinableCombat(FrozenCombat, ABC): - def __init__(self, freeze_duration: timedelta, flights: list[Flight]) -> None: - super().__init__(freeze_duration) - self.flights = flights - - @abstractmethod - def joinable_by(self, flight: Flight) -> bool: - ... - - def join(self, flight: Flight) -> None: - assert isinstance(flight.state, InFlight) - assert not isinstance(flight.state, InCombat) - self.flights.append(flight) - flight.set_state(InCombat(flight.state, self)) - - def iter_flights(self) -> Iterator[Flight]: - yield from self.flights diff --git a/game/sim/combat/samengagementzones.py b/game/sim/combat/samengagementzones.py deleted file mode 100644 index fcaeefa36..000000000 --- a/game/sim/combat/samengagementzones.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from typing import TYPE_CHECKING - -from dcs import Point -from shapely.ops import unary_union - -from game.utils import dcs_to_shapely_point - -if TYPE_CHECKING: - from game.theater import ConflictTheater, TheaterGroundObject - from game.threatzones import ThreatPoly - - -class SamEngagementZones: - def __init__( - self, - threat_zones: ThreatPoly, - individual_zones: list[tuple[TheaterGroundObject, ThreatPoly]], - ) -> None: - self.threat_zones = threat_zones - self.individual_zones = individual_zones - - def covers(self, position: Point) -> bool: - return self.threat_zones.intersects(dcs_to_shapely_point(position)) - - def iter_threatening_sams(self, position: Point) -> Iterator[TheaterGroundObject]: - for tgo, zone in self.individual_zones: - if zone.intersects(dcs_to_shapely_point(position)): - yield tgo - - @classmethod - def from_theater(cls, theater: ConflictTheater, player: bool) -> SamEngagementZones: - commit_regions = [] - individual_zones = [] - for cp in theater.control_points_for(player): - for tgo in cp.connected_objectives: - if (region := tgo.threat_poly()) is not None: - commit_regions.append(region) - individual_zones.append((tgo, region)) - return SamEngagementZones(unary_union(commit_regions), individual_zones) diff --git a/game/sim/gameloop.py b/game/sim/gameloop.py deleted file mode 100644 index a15886659..000000000 --- a/game/sim/gameloop.py +++ /dev/null @@ -1,113 +0,0 @@ -from __future__ import annotations - -import logging -from contextlib import contextmanager -from datetime import datetime, timedelta -from pathlib import Path -from typing import Iterator, TYPE_CHECKING - -from .gamelooptimer import GameLoopTimer -from .gameupdatecallbacks import GameUpdateCallbacks -from .gameupdateevents import GameUpdateEvents -from .missionsimulation import MissionSimulation, SimulationAlreadyCompletedError -from .simspeedsetting import SimSpeedSetting - -if TYPE_CHECKING: - from game import Game - from game.debriefing import Debriefing - - -class GameLoop: - def __init__(self, game: Game, callbacks: GameUpdateCallbacks) -> None: - self.game = game - self.callbacks = callbacks - self.timer = GameLoopTimer(self.tick) - self.sim = MissionSimulation(self.game) - self.events = GameUpdateEvents() - self.last_update_time = datetime.now() - self.started = False - self.completed = False - - @property - def current_time_in_sim(self) -> datetime: - return self.sim.time - - @property - def elapsed_time(self) -> timedelta: - return self.sim.time - self.game.conditions.start_time - - def start(self) -> None: - if self.started: - raise RuntimeError("Cannot start game loop because it has already started") - self.game.save_manager.save_pre_sim_checkpoint() - self.started = True - self.sim.begin_simulation() - - def pause(self) -> None: - self.set_simulation_speed(SimSpeedSetting.PAUSED) - - def set_simulation_speed(self, simulation_speed: SimSpeedSetting) -> None: - self.timer.stop() - if simulation_speed != self.timer.simulation_speed: - logging.info(f"Speed changed to {simulation_speed}") - if not self.started and simulation_speed is not SimSpeedSetting.PAUSED: - self.start() - self.timer.set_speed(simulation_speed) - - @contextmanager - def paused_sim(self) -> Iterator[None]: - with self.timer.locked_pause(): - yield - - def run_to_first_contact(self) -> None: - self.pause() - if not self.started: - self.start() - logging.info("Running sim to first contact") - while not self.completed: - self.tick(suppress_events=True) - - def pause_and_generate_miz(self, output: Path) -> None: - self.pause() - if not self.started: - self.start() - self.sim.generate_miz(output) - - def pause_and_debrief(self, state_path: Path, force_end: bool) -> Debriefing: - self.pause() - return self.sim.debrief_current_state(state_path, force_end) - - def complete_with_results(self, debriefing: Debriefing) -> None: - self.pause() - self.sim.process_results(debriefing, self.events) - self.completed = True - self.send_update(rate_limit=False) - - def send_update(self, rate_limit: bool) -> None: - # We don't skip empty events because we still want the tick in the Qt part of - # the UI, which will update things like the current simulation time. The time - # probably be an "event" of its own. For now the websocket endpoint will filter - # out empty events to avoid the map handling unnecessary events, but we still - # pass the events through to Qt. - now = datetime.now() - time_since_update = now - self.last_update_time - if not rate_limit or time_since_update >= timedelta(seconds=1 / 60): - self.callbacks.on_update(self.events) - self.events = GameUpdateEvents() - self.last_update_time = now - - def tick(self, suppress_events: bool = False) -> None: - if not self.started: - raise RuntimeError("Attempted to tick game loop before initialization") - try: - self.sim.tick(self.events) - self.completed = self.events.simulation_complete - if not suppress_events: - self.send_update(rate_limit=True) - if self.completed: - self.pause() - self.send_update(rate_limit=False) - logging.info(f"Simulation completed at {self.sim.time}") - self.callbacks.on_simulation_complete() - except SimulationAlreadyCompletedError: - logging.exception("Attempted to tick already completed sim") diff --git a/game/sim/gamelooptimer.py b/game/sim/gamelooptimer.py deleted file mode 100644 index f52f0835a..000000000 --- a/game/sim/gamelooptimer.py +++ /dev/null @@ -1,61 +0,0 @@ -from collections.abc import Iterator -from contextlib import contextmanager -from threading import RLock, Timer -from typing import Callable, Optional - -from .simspeedsetting import SimSpeedSetting - - -class GameLoopTimer: - def __init__(self, callback: Callable[[], None]) -> None: - self.callback = callback - self.simulation_speed = SimSpeedSetting.PAUSED - self._timer: Optional[Timer] = None - # Reentrant to allow a single thread nested use of `locked_pause`. - self._timer_lock = RLock() - - def set_speed(self, simulation_speed: SimSpeedSetting) -> None: - with self._timer_lock: - self._set_speed(simulation_speed) - - def stop(self) -> None: - with self._timer_lock: - self._stop() - - @contextmanager - def locked_pause(self) -> Iterator[None]: - # NB: This must be a locked _pause_ and not a locked speed, because nested use - # of this method is allowed. That's okay if all nested callers set the same - # speed (paused), but not okay if a parent locks a speed and a child locks - # another speed. That's okay though, because we're unlikely to ever want to lock - # any speed but paused. - with self._timer_lock: - old_speed = self.simulation_speed - self._stop() - try: - yield - finally: - self._set_speed(old_speed) - - def _set_speed(self, simulation_speed: SimSpeedSetting) -> None: - self._stop() - self.simulation_speed = simulation_speed - self._recreate_timer() - - def _stop(self) -> None: - if self._timer is not None: - self._timer.cancel() - - def _recreate_timer(self) -> None: - self._stop() - factor = self.simulation_speed.speed_factor - if not factor: - self._timer = None - return None - self._timer = Timer(1 / factor, self._tick) - self._timer.start() - - def _tick(self) -> None: - self.callback() - with self._timer_lock: - self._recreate_timer() diff --git a/game/sim/gameupdatecallbacks.py b/game/sim/gameupdatecallbacks.py deleted file mode 100644 index 76e631399..000000000 --- a/game/sim/gameupdatecallbacks.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from collections.abc import Callable -from dataclasses import dataclass - -from game.sim.gameupdateevents import GameUpdateEvents - - -# Ought to be frozen but mypy can't handle that: -# https://github.com/python/mypy/issues/5485 -@dataclass -class GameUpdateCallbacks: - on_simulation_complete: Callable[[], None] - on_update: Callable[[GameUpdateEvents], None] diff --git a/game/sim/gameupdateevents.py b/game/sim/gameupdateevents.py deleted file mode 100644 index 4721dc59b..000000000 --- a/game/sim/gameupdateevents.py +++ /dev/null @@ -1,152 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import TYPE_CHECKING -from uuid import UUID - -from dcs import Point - -if TYPE_CHECKING: - from game import Game - from game.ato import Flight, Package - from game.navmesh import NavMesh - from game.sim.combat import FrozenCombat - from game.theater import ControlPoint, FrontLine, TheaterGroundObject - from game.threatzones import ThreatZones - from game.theater.iadsnetwork.iadsnetwork import IadsNetworkNode - - -@dataclass -class GameUpdateEvents: - simulation_complete = False - new_combats: list[FrozenCombat] = field(default_factory=list) - updated_combats: list[FrozenCombat] = field(default_factory=list) - ended_combats: list[FrozenCombat] = field(default_factory=list) - updated_flight_positions: list[tuple[Flight, Point]] = field(default_factory=list) - navmesh_updates: dict[bool, NavMesh] = field(default_factory=dict) - unculled_zones_updated: list[Point] = field(default_factory=list) - threat_zones_updated: dict[bool, ThreatZones] = field(default_factory=dict) - new_flights: set[Flight] = field(default_factory=set) - updated_flights: set[Flight] = field(default_factory=set) - deleted_flights: set[UUID] = field(default_factory=set) - selected_flight: UUID | None = None - deselected_flight: bool = False - updated_front_lines: set[FrontLine] = field(default_factory=set) - deleted_front_lines: set[UUID] = field(default_factory=set) - updated_tgos: set[TheaterGroundObject] = field(default_factory=set) - updated_control_points: set[ControlPoint] = field(default_factory=set) - updated_iads: set[IadsNetworkNode] = field(default_factory=set) - deleted_iads_connections: set[UUID] = field(default_factory=set) - reset_on_map_center: Point | None = None - game_unloaded: bool = False - new_turn: bool = False - shutting_down: bool = False - - @property - def empty(self) -> bool: - return self == GameUpdateEvents() - - def complete_simulation(self) -> GameUpdateEvents: - self.simulation_complete = True - return self - - def new_combat(self, combat: FrozenCombat) -> GameUpdateEvents: - self.new_combats.append(combat) - return self - - def update_combat(self, combat: FrozenCombat) -> GameUpdateEvents: - self.updated_combats.append(combat) - return self - - def end_combat(self, combat: FrozenCombat) -> GameUpdateEvents: - self.ended_combats.append(combat) - return self - - def update_flight_position( - self, flight: Flight, new_position: Point - ) -> GameUpdateEvents: - self.updated_flight_positions.append((flight, new_position)) - return self - - def update_navmesh(self, player: bool, navmesh: NavMesh) -> GameUpdateEvents: - self.navmesh_updates[player] = navmesh - return self - - def update_unculled_zones(self, zones: list[Point]) -> GameUpdateEvents: - self.unculled_zones_updated = zones - return self - - def update_threat_zones(self, player: bool, zones: ThreatZones) -> GameUpdateEvents: - self.threat_zones_updated[player] = zones - return self - - def new_flight(self, flight: Flight) -> GameUpdateEvents: - self.new_flights.add(flight) - return self - - def update_flight(self, flight: Flight) -> GameUpdateEvents: - self.updated_flights.add(flight) - return self - - def update_flights_in_package(self, package: Package) -> GameUpdateEvents: - self.updated_flights.update({f for f in package.flights}) - return self - - def delete_flight(self, flight: Flight) -> GameUpdateEvents: - self.deleted_flights.add(flight.id) - return self - - def delete_flights_in_package(self, package: Package) -> GameUpdateEvents: - self.deleted_flights.update({f.id for f in package.flights}) - return self - - def select_flight(self, flight: Flight) -> GameUpdateEvents: - self.selected_flight = flight.id - self.deselected_flight = False - return self - - def deselect_flight(self) -> GameUpdateEvents: - self.deselected_flight = True - self.selected_flight = None - return self - - def update_front_line(self, front_line: FrontLine) -> GameUpdateEvents: - self.updated_front_lines.add(front_line) - return self - - def delete_front_line(self, front_line: FrontLine) -> GameUpdateEvents: - self.deleted_front_lines.add(front_line.id) - return self - - def update_tgo(self, tgo: TheaterGroundObject) -> GameUpdateEvents: - self.updated_tgos.add(tgo) - return self - - def update_control_point(self, control_point: ControlPoint) -> GameUpdateEvents: - self.updated_control_points.add(control_point) - return self - - def update_iads_node(self, iads_node: IadsNetworkNode) -> GameUpdateEvents: - self.updated_iads.add(iads_node) - return self - - def delete_iads_connection(self, connection_id: UUID) -> GameUpdateEvents: - self.deleted_iads_connections.add(connection_id) - return self - - def game_loaded(self, game: Game | None) -> GameUpdateEvents: - if game is None: - self.game_unloaded = True - self.reset_on_map_center = None - else: - self.reset_on_map_center = game.theater.terrain.map_view_default.position - self.game_unloaded = False - return self - - def begin_new_turn(self) -> GameUpdateEvents: - self.new_turn = True - return self - - def shut_down(self) -> GameUpdateEvents: - self.shutting_down = True - return self diff --git a/game/sim/missionresultsprocessor.py b/game/sim/missionresultsprocessor.py deleted file mode 100644 index 54c0a6f76..000000000 --- a/game/sim/missionresultsprocessor.py +++ /dev/null @@ -1,374 +0,0 @@ -from __future__ import annotations - -import logging -from typing import TYPE_CHECKING - -from game.debriefing import Debriefing -from game.ground_forces.combat_stance import CombatStance -from game.theater import ControlPoint -from .gameupdateevents import GameUpdateEvents -from ..ato.airtaaskingorder import AirTaskingOrder - -if TYPE_CHECKING: - from ..game import Game - - -MINOR_DEFEAT_INFLUENCE = 0.1 -DEFEAT_INFLUENCE = 0.3 -STRONG_DEFEAT_INFLUENCE = 0.5 - - -class MissionResultsProcessor: - def __init__(self, game: Game) -> None: - self.game = game - - def commit(self, debriefing: Debriefing, events: GameUpdateEvents) -> None: - logging.info("Committing mission results") - self.commit_air_losses(debriefing) - self.commit_pilot_experience() - self.commit_front_line_losses(debriefing) - self.commit_convoy_losses(debriefing) - self.commit_cargo_ship_losses(debriefing) - self.commit_airlift_losses(debriefing) - self.commit_ground_losses(debriefing, events) - self.commit_damaged_runways(debriefing) - self.commit_captures(debriefing, events) - self.commit_front_line_battle_impact(debriefing, events) - self.commit_unit_damage(debriefing) - self.record_carcasses(debriefing) - - def commit_air_losses(self, debriefing: Debriefing) -> None: - for loss in debriefing.air_losses.losses: - if loss.pilot is not None and ( - not loss.pilot.player - or not self.game.settings.invulnerable_player_pilots - ): - loss.pilot.kill() - squadron = loss.flight.squadron - aircraft = loss.flight.unit_type - available = squadron.owned_aircraft - if available <= 0: - logging.error( - f"Found killed {aircraft} from {squadron} but that airbase has " - "none available." - ) - continue - - logging.info(f"{aircraft} destroyed from {squadron}") - squadron.owned_aircraft -= 1 - - @staticmethod - def _commit_pilot_experience(ato: AirTaskingOrder) -> None: - for package in ato.packages: - for flight in package.flights: - for idx, pilot in enumerate(flight.roster.iter_pilots()): - if pilot is None: - logging.error( - f"Cannot award experience to pilot #{idx} of {flight} " - "because no pilot is assigned" - ) - continue - pilot.record.missions_flown += 1 - - def commit_pilot_experience(self) -> None: - self._commit_pilot_experience(self.game.blue.ato) - self._commit_pilot_experience(self.game.red.ato) - - @staticmethod - def commit_front_line_losses(debriefing: Debriefing) -> None: - for loss in debriefing.front_line_losses: - unit_type = loss.unit_type - control_point = loss.origin - available = control_point.base.total_units_of_type(unit_type) - if available <= 0: - logging.error( - f"Found killed {unit_type} from {control_point} but that " - "airbase has none available." - ) - continue - - logging.info(f"{unit_type} destroyed from {control_point}") - control_point.base.armor[unit_type] -= 1 - - @staticmethod - def commit_convoy_losses(debriefing: Debriefing) -> None: - for loss in debriefing.convoy_losses: - unit_type = loss.unit_type - convoy = loss.convoy - available = loss.convoy.units.get(unit_type, 0) - convoy_name = f"convoy from {convoy.origin} to {convoy.destination}" - if available <= 0: - logging.error( - f"Found killed {unit_type} in {convoy_name} but that convoy has " - "none available." - ) - continue - - logging.info(f"{unit_type} destroyed in {convoy_name}") - convoy.kill_unit(unit_type) - - @staticmethod - def commit_cargo_ship_losses(debriefing: Debriefing) -> None: - for ship in debriefing.cargo_ship_losses: - logging.info( - f"All units destroyed in cargo ship from {ship.origin} to " - f"{ship.destination}." - ) - ship.kill_all() - - @staticmethod - def commit_airlift_losses(debriefing: Debriefing) -> None: - for loss in debriefing.airlift_losses: - transfer = loss.transfer - airlift_name = f"airlift from {transfer.origin} to {transfer.destination}" - for unit_type in loss.cargo: - try: - transfer.kill_unit(unit_type) - logging.info(f"{unit_type} destroyed in {airlift_name}") - except KeyError: - logging.exception( - f"Found killed {unit_type} in {airlift_name} but that airlift " - "has none available." - ) - - @staticmethod - def commit_ground_losses(debriefing: Debriefing, events: GameUpdateEvents) -> None: - killed_ground_objects = [] - for ground_object_loss in debriefing.ground_object_losses: - ground_object_loss.theater_unit.kill(events) - killed_ground_objects.append(ground_object_loss.theater_unit.ground_object) - for scenery_object_loss in debriefing.scenery_object_losses: - scenery_object_loss.ground_unit.kill(events) - killed_ground_objects.append(scenery_object_loss.ground_unit.ground_object) - - # Update the IADS network if any participant had losses - iads_network = debriefing.game.theater.iads_network - for killed_ground_object in killed_ground_objects: - if killed_ground_object in iads_network.participating: - iads_network.update_network(events) - return - - @staticmethod - def commit_damaged_runways(debriefing: Debriefing) -> None: - for damaged_runway in debriefing.damaged_runways: - damaged_runway.damage_runway() - - def commit_captures(self, debriefing: Debriefing, events: GameUpdateEvents) -> None: - for captured in debriefing.base_captures: - try: - if captured.captured_by_player: - self.game.message( - f"{captured.control_point} captured!", - f"We took control of {captured.control_point}.", - ) - else: - self.game.message( - f"{captured.control_point} lost!", - f"The enemy took control of {captured.control_point}.", - ) - - captured.control_point.capture( - self.game, events, captured.captured_by_player - ) - logging.info(f"Will run redeploy for {captured.control_point}") - self.redeploy_units(captured.control_point) - except Exception: - logging.exception(f"Could not process base capture {captured}") - - def record_carcasses(self, debriefing: Debriefing) -> None: - for destroyed_unit in debriefing.state_data.destroyed_statics: - self.game.add_destroyed_units(destroyed_unit) - - def commit_front_line_battle_impact( - self, debriefing: Debriefing, events: GameUpdateEvents - ) -> None: - for cp in self.game.theater.player_points(): - enemy_cps = [e for e in cp.connected_points if not e.captured] - for enemy_cp in enemy_cps: - front_line = cp.front_line_with(enemy_cp) - front_line.update_position() - events.update_front_line(front_line) - - print( - "Compute frontline progression for : " - + cp.name - + " to " - + enemy_cp.name - ) - - delta = 0.0 - player_won = True - status_msg: str = "" - ally_casualties = debriefing.casualty_count(cp) - enemy_casualties = debriefing.casualty_count(enemy_cp) - ally_units_alive = cp.base.total_armor - enemy_units_alive = enemy_cp.base.total_armor - - print(f"Remaining allied units: {ally_units_alive}") - print(f"Remaining enemy units: {enemy_units_alive}") - print(f"Allied casualties {ally_casualties}") - print(f"Enemy casualties {enemy_casualties}") - - ratio = (1.0 + enemy_casualties) / (1.0 + ally_casualties) - - player_aggresive = cp.stances[enemy_cp.id] in [ - CombatStance.AGGRESSIVE, - CombatStance.ELIMINATION, - CombatStance.BREAKTHROUGH, - ] - - if ally_units_alive == 0: - player_won = False - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"No allied units alive at {cp.name}-{enemy_cp.name} frontline. Allied ground forces suffer a strong defeat." - elif enemy_units_alive == 0: - player_won = True - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"No enemy units alive at {cp.name}-{enemy_cp.name} frontline. Allied ground forces win a strong victory." - elif cp.stances[enemy_cp.id] == CombatStance.RETREAT: - player_won = False - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"Allied forces are retreating along the {cp.name}-{enemy_cp.name} frontline, suffering a strong defeat." - else: - if enemy_casualties > ally_casualties: - player_won = True - if cp.stances[enemy_cp.id] == CombatStance.BREAKTHROUGH: - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"Allied forces break through the {cp.name}-{enemy_cp.name} frontline, winning a strong victory" - else: - if ratio > 3: - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"Enemy casualties massively outnumber allied casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces win a strong victory." - elif ratio < 1.5: - delta = MINOR_DEFEAT_INFLUENCE - status_msg = f"Enemy casualties minorly outnumber allied casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces win a minor victory." - else: - delta = DEFEAT_INFLUENCE - status_msg = f"Enemy casualties outnumber allied casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces claim a victory." - elif ally_casualties > enemy_casualties: - if ( - ally_units_alive > 2 * enemy_units_alive - and player_aggresive - ): - # Even with casualties if the enemy is overwhelmed, they are going to lose ground - player_won = True - delta = MINOR_DEFEAT_INFLUENCE - status_msg = f"Despite suffering losses, allied forces still outnumber enemy forces along the {cp.name}-{enemy_cp.name} frontline. Due to allied force's aggressive posture, allied forces claim a minor victory." - elif ( - ally_units_alive > 3 * enemy_units_alive - and player_aggresive - ): - player_won = True - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"Despite suffering losses, allied forces still heavily outnumber enemy forces along the {cp.name}-{enemy_cp.name} frontline. Due to allied force's aggressive posture, allied forces claim a major victory." - else: - # But if the enemy is not outnumbered, we lose - player_won = False - if cp.stances[enemy_cp.id] == CombatStance.BREAKTHROUGH: - delta = STRONG_DEFEAT_INFLUENCE - status_msg = f"Allied casualties outnumber enemy casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces have overextended themselves, suffering a major defeat." - else: - delta = DEFEAT_INFLUENCE - status_msg = f"Allied casualties outnumber enemy casualties along the {cp.name}-{enemy_cp.name} frontline. Allied forces suffer a defeat." - - # No progress with defensive strategies - if player_won and cp.stances[enemy_cp.id] in [ - CombatStance.DEFENSIVE, - CombatStance.AMBUSH, - ]: - print( - f"Allied forces have adopted a defensive stance along the {cp.name}-{enemy_cp.name} " - f"frontline, making only limited progress." - ) - delta = MINOR_DEFEAT_INFLUENCE - - # Handle the case where there are no casualties at all on either side but both sides still have units - if delta == 0.0: - print(status_msg) - self.game.message( - "Frontline Report", - f"Our ground forces from {cp.name} reached a stalemate with enemy forces from {enemy_cp.name}.", - ) - else: - if player_won: - print(status_msg) - cp.base.affect_strength(delta) - enemy_cp.base.affect_strength(-delta) - self.game.message( - "Frontline Report", - f"Our ground forces from {cp.name} are making progress toward {enemy_cp.name}. {status_msg}", - ) - else: - print(status_msg) - enemy_cp.base.affect_strength(delta) - cp.base.affect_strength(-delta) - self.game.message( - "Frontline Report", - f"Our ground forces from {cp.name} are losing ground against the enemy forces from " - f"{enemy_cp.name}. {status_msg}", - ) - - @staticmethod - def commit_unit_damage(debriefing: Debriefing) -> None: - for damaged_unit in debriefing.unit_hit_point_update_events(): - logging.info( - f"{damaged_unit.unit.theater_unit.name} damaged, setting hit points to {damaged_unit.hit_points}" - ) - damaged_unit.commit() - - def redeploy_units(self, cp: ControlPoint) -> None: - """ " - Auto redeploy units to newly captured base - """ - - ally_connected_cps = [ - ocp for ocp in cp.connected_points if cp.captured == ocp.captured - ] - enemy_connected_cps = [ - ocp for ocp in cp.connected_points if cp.captured != ocp.captured - ] - - # If the newly captured cp does not have enemy connected cp, - # then it is not necessary to redeploy frontline units there. - if len(enemy_connected_cps) == 0: - return - - # From each ally cp, send reinforcements - for ally_cp in ally_connected_cps: - self.redeploy_between(cp, ally_cp) - - def redeploy_between(self, destination: ControlPoint, source: ControlPoint) -> None: - total_units_redeployed = 0 - moved_units = {} - - if source.has_active_frontline or not destination.captured: - # If there are still active front lines to defend at the - # transferring CP we should not transfer all units. - # - # Opfor also does not transfer all of their units. - # TODO: Balance the CPs rather than moving half from everywhere. - move_factor = 0.5 - else: - # Otherwise we can move everything. - move_factor = 1 - - for frontline_unit, count in source.base.armor.items(): - moved_units[frontline_unit] = int(count * move_factor) - total_units_redeployed = total_units_redeployed + int(count * move_factor) - - destination.base.commission_units(moved_units) - source.base.commit_losses(moved_units) - - # Also transfer pending deliveries. - for unit_type, count in source.ground_unit_orders.units.items(): - move_count = int(count * move_factor) - source.ground_unit_orders.sell({unit_type: move_count}) - destination.ground_unit_orders.order({unit_type: move_count}) - total_units_redeployed += move_count - - if total_units_redeployed > 0: - self.game.message( - "Units redeployed", - f"{total_units_redeployed} units have been redeployed from " - f"{source.name} to {destination.name}", - ) diff --git a/game/sim/missionsimulation.py b/game/sim/missionsimulation.py deleted file mode 100644 index cef32e19d..000000000 --- a/game/sim/missionsimulation.py +++ /dev/null @@ -1,80 +0,0 @@ -from __future__ import annotations - -import json -from datetime import timedelta -from pathlib import Path -from typing import Optional, TYPE_CHECKING - -from game.debriefing import Debriefing -from game.missiongenerator import MissionGenerator -from game.unitmap import UnitMap -from .aircraftsimulation import AircraftSimulation -from .missionresultsprocessor import MissionResultsProcessor -from ..profiling import logged_duration - -if TYPE_CHECKING: - from game import Game - from .gameupdateevents import GameUpdateEvents - - -TICK = timedelta(seconds=1) - - -class SimulationAlreadyCompletedError(RuntimeError): - def __init__(self) -> None: - super().__init__("Simulation already completed") - - -class MissionSimulation: - def __init__(self, game: Game) -> None: - self.game = game - self.unit_map: Optional[UnitMap] = None - self.aircraft_simulation = AircraftSimulation(self.game) - self.completed = False - self.time = self.game.conditions.start_time - - def begin_simulation(self) -> None: - self.time = self.game.conditions.start_time - self.aircraft_simulation.begin_simulation() - - def tick(self, events: GameUpdateEvents) -> GameUpdateEvents: - self.time += TICK - if self.completed: - raise RuntimeError("Simulation already completed") - self.aircraft_simulation.on_game_tick(events, self.time, TICK) - self.completed = events.simulation_complete - return events - - def generate_miz(self, output: Path) -> None: - with logged_duration("Mission generation"): - self.unit_map = MissionGenerator(self.game, self.time).generate_miz(output) - - def debrief_current_state( - self, state_path: Path, force_end: bool = False - ) -> Debriefing: - if self.unit_map is None: - raise RuntimeError( - "Simulation has no unit map. Results processing began before a mission " - "was generated." - ) - - with state_path.open("r", encoding="utf-8") as state_file: - data = json.load(state_file) - if force_end: - data["mission_ended"] = True - debriefing = Debriefing(data, self.game, self.unit_map) - debriefing.merge_simulation_results(self.aircraft_simulation.results) - return debriefing - - def process_results(self, debriefing: Debriefing, events: GameUpdateEvents) -> None: - if self.unit_map is None: - raise RuntimeError( - "Simulation has no unit map. Results processing began before a mission " - "was generated." - ) - - self.game.save_last_turn_state() - MissionResultsProcessor(self.game).commit(debriefing, events) - - def finish(self) -> None: - self.unit_map = None diff --git a/game/sim/simspeedsetting.py b/game/sim/simspeedsetting.py deleted file mode 100644 index 954270466..000000000 --- a/game/sim/simspeedsetting.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from enum import Enum, unique - - -@unique -class SimSpeedSetting(Enum): - PAUSED = (0, "Paused") - X1 = (1, "1x") - X2 = (2, "2x") - X5 = (5, "5x") - X10 = (10, "10x") - X100 = (100, "100x") - X1000 = (1000, "1000x") - - def __init__(self, speed_factor: int, text: str) -> None: - self.speed_factor = speed_factor - self.text = text - - def __str__(self) -> str: - return self.text - - @classmethod - def from_factor(cls, speed_factor: int) -> SimSpeedSetting: - for setting in SimSpeedSetting: - if setting.speed_factor == speed_factor: - return setting - raise ValueError diff --git a/game/sim/simulationresults.py b/game/sim/simulationresults.py deleted file mode 100644 index 9c2973198..000000000 --- a/game/sim/simulationresults.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from typing import TYPE_CHECKING - -from game.unitmap import FlyingUnit - -if TYPE_CHECKING: - from game.ato import Flight - from game.squadrons import Pilot - - -# TODO: Serialize for bug reproducibility. -# Any bugs filed that can only be reproduced with auto-resolved combat results will not -# be reproducible since we cannot replay the auto-resolution that the player saw. We -# need to be able to serialize this data so bug repro can include the auto-resolved -# results. -@dataclass -class SimulationResults: - air_losses: list[FlyingUnit] = field(default_factory=list) - - def kill_pilot(self, flight: Flight, pilot: Pilot) -> None: - self.air_losses.append(FlyingUnit(flight, pilot)) diff --git a/game/squadrons/__init__.py b/game/squadrons/__init__.py deleted file mode 100644 index 99fdd47af..000000000 --- a/game/squadrons/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .airwing import AirWing -from .pilot import Pilot -from .squadron import Squadron diff --git a/game/squadrons/airwing.py b/game/squadrons/airwing.py deleted file mode 100644 index 70b0c7c42..000000000 --- a/game/squadrons/airwing.py +++ /dev/null @@ -1,144 +0,0 @@ -from __future__ import annotations - -import itertools -from collections import defaultdict -from typing import Iterator, Optional, Sequence, TYPE_CHECKING - -from game.ato.closestairfields import ObjectiveDistanceCache -from game.dcs.aircrafttype import AircraftType -from .squadrondefloader import SquadronDefLoader -from ..campaignloader.squadrondefgenerator import SquadronDefGenerator -from ..factions.faction import Faction -from ..theater import ControlPoint, MissionTarget - -if TYPE_CHECKING: - from game.game import Game - from ..ato.flighttype import FlightType - from .squadron import Squadron - - -class AirWing: - def __init__(self, player: bool, game: Game, faction: Faction) -> None: - self.player = player - self.squadrons: dict[AircraftType, list[Squadron]] = defaultdict(list) - self.squadron_defs = SquadronDefLoader(game, faction).load() - self.squadron_def_generator = SquadronDefGenerator(faction) - self.settings = game.settings - - def unclaim_squadron_def(self, squadron: Squadron) -> None: - if squadron.aircraft in self.squadron_defs: - for squadron_def in self.squadron_defs[squadron.aircraft]: - if squadron_def.claimed and squadron_def.name == squadron.name: - squadron_def.claimed = False - - def add_squadron(self, squadron: Squadron) -> None: - self.squadrons[squadron.aircraft].append(squadron) - - def squadrons_for(self, aircraft: AircraftType) -> Sequence[Squadron]: - return self.squadrons[aircraft] - - def can_auto_plan(self, task: FlightType) -> bool: - try: - next(self.auto_assignable_for_task(task)) - return True - except StopIteration: - return False - - def best_squadrons_for( - self, location: MissionTarget, task: FlightType, size: int, this_turn: bool - ) -> list[Squadron]: - airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location) - best_aircraft = AircraftType.priority_list_for_task(task) - ordered: list[Squadron] = [] - for control_point in airfield_cache.operational_airfields: - if control_point.captured != self.player: - continue - if control_point.ferry_only: - continue - capable_at_base = [] - for squadron in control_point.squadrons: - if squadron.can_auto_assign_mission(location, task, size, this_turn): - capable_at_base.append(squadron) - if squadron.aircraft not in best_aircraft: - # If it is not already in the list it should be the last one - best_aircraft.append(squadron.aircraft) - - ordered.extend( - sorted( - capable_at_base, - key=lambda s: best_aircraft.index(s.aircraft), - ) - ) - - return sorted( - ordered, - key=lambda s: ( - # This looks like the opposite of what we want because False sorts - # before True. - s.primary_task != task, - s.location.distance_to(location), - ), - ) - - def best_squadron_for( - self, location: MissionTarget, task: FlightType, size: int, this_turn: bool - ) -> Optional[Squadron]: - for squadron in self.best_squadrons_for(location, task, size, this_turn): - return squadron - return None - - def best_available_aircrafts_for(self, task: FlightType) -> list[AircraftType]: - """Returns an ordered list of available aircrafts for the given task""" - aircrafts = [] - best_aircraft_for_task = AircraftType.priority_list_for_task(task) - for aircraft, squadrons in self.squadrons.items(): - for squadron in squadrons: - if squadron.location.ferry_only: - continue - if squadron.untasked_aircraft and squadron.capable_of(task): - aircrafts.append(aircraft) - if aircraft not in best_aircraft_for_task: - best_aircraft_for_task.append(aircraft) - break - # Sort the list ordered by the best capability - return sorted( - aircrafts, - key=lambda ac: best_aircraft_for_task.index(ac), - ) - - def auto_assignable_for_task(self, task: FlightType) -> Iterator[Squadron]: - for squadron in self.iter_squadrons(): - if squadron.can_auto_assign(task): - yield squadron - - def auto_assignable_for_task_at( - self, task: FlightType, base: ControlPoint - ) -> Iterator[Squadron]: - for squadron in self.iter_squadrons(): - if squadron.can_auto_assign(task) and squadron.location == base: - yield squadron - - def squadron_for(self, aircraft: AircraftType) -> Squadron: - return self.squadrons_for(aircraft)[0] - - def iter_squadrons(self) -> Iterator[Squadron]: - return itertools.chain.from_iterable(self.squadrons.values()) - - def squadron_at_index(self, index: int) -> Squadron: - return list(self.iter_squadrons())[index] - - def populate_for_turn_0(self) -> None: - for squadron in self.iter_squadrons(): - squadron.populate_for_turn_0() - - def end_turn(self) -> None: - for squadron in self.iter_squadrons(): - squadron.end_turn() - - def reset(self) -> None: - for squadron in self.iter_squadrons(): - squadron.return_all_pilots_and_aircraft() - - @property - def size(self) -> int: - return sum(len(s) for s in self.squadrons.values()) diff --git a/game/squadrons/operatingbases.py b/game/squadrons/operatingbases.py deleted file mode 100644 index 181e38677..000000000 --- a/game/squadrons/operatingbases.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -import dataclasses -from dataclasses import dataclass - -from game.dcs.aircrafttype import AircraftType - - -@dataclass(frozen=True) -class OperatingBases: - shore: bool - carrier: bool - lha: bool - - @classmethod - def default_for_aircraft(cls, aircraft: AircraftType) -> OperatingBases: - if aircraft.dcs_unit_type.helicopter: - # Helicopters operate from anywhere by default. - return OperatingBases(shore=True, carrier=True, lha=True) - if aircraft.lha_capable: - # Marine aircraft operate from LHAs and the shore by default. - return OperatingBases(shore=True, carrier=False, lha=True) - if aircraft.carrier_capable: - # Carrier aircraft operate from carriers by default. - return OperatingBases(shore=False, carrier=True, lha=False) - # And the rest are only capable of shore operation. - return OperatingBases(shore=True, carrier=False, lha=False) - - @classmethod - def from_yaml(cls, aircraft: AircraftType, data: dict[str, bool]) -> OperatingBases: - return dataclasses.replace( - OperatingBases.default_for_aircraft(aircraft), **data - ) diff --git a/game/squadrons/pilot.py b/game/squadrons/pilot.py deleted file mode 100644 index dd3bac279..000000000 --- a/game/squadrons/pilot.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from enum import unique, Enum - -from faker import Faker - - -@dataclass -class PilotRecord: - missions_flown: int = field(default=0) - - -@unique -class PilotStatus(Enum): - Active = "Active" - OnLeave = "On leave" - Dead = "Dead" - - -@dataclass -class Pilot: - name: str - player: bool = field(default=False) - status: PilotStatus = field(default=PilotStatus.Active) - record: PilotRecord = field(default_factory=PilotRecord) - - @property - def alive(self) -> bool: - return self.status is not PilotStatus.Dead - - @property - def on_leave(self) -> bool: - return self.status is PilotStatus.OnLeave - - def send_on_leave(self) -> None: - if self.status is not PilotStatus.Active: - raise RuntimeError("Only active pilots may be sent on leave") - self.status = PilotStatus.OnLeave - - def return_from_leave(self) -> None: - if self.status is not PilotStatus.OnLeave: - raise RuntimeError("Only pilots on leave may be returned from leave") - self.status = PilotStatus.Active - - def kill(self) -> None: - self.status = PilotStatus.Dead - - @classmethod - def random(cls, faker: Faker) -> Pilot: - return Pilot(faker.name()) diff --git a/game/squadrons/squadron.py b/game/squadrons/squadron.py deleted file mode 100644 index 1506617ab..000000000 --- a/game/squadrons/squadron.py +++ /dev/null @@ -1,456 +0,0 @@ -from __future__ import annotations - -import logging -import random -from collections.abc import Iterable -from dataclasses import dataclass, field -from datetime import datetime -from typing import Optional, Sequence, TYPE_CHECKING -from uuid import uuid4, UUID - -from faker import Faker - -from game.ato import Flight, FlightType, Package -from game.settings import AutoAtoBehavior, Settings -from .pilot import Pilot, PilotStatus -from ..db.database import Database -from ..utils import meters - -if TYPE_CHECKING: - from game import Game - from game.coalition import Coalition - from game.dcs.aircrafttype import AircraftType - from game.theater import ControlPoint, MissionTarget - from .operatingbases import OperatingBases - from .squadrondef import SquadronDef - - -@dataclass -class Squadron: - id: UUID = field(init=False, default_factory=uuid4) - - name: str - nickname: Optional[str] - country: str - role: str - aircraft: AircraftType - max_size: int - livery: Optional[str] - primary_task: FlightType - auto_assignable_mission_types: set[FlightType] - operating_bases: OperatingBases - female_pilot_percentage: int - - #: The pool of pilots that have not yet been assigned to the squadron. This only - #: happens when a preset squadron defines more preset pilots than the squadron limit - #: allows. This pool will be consumed before random pilots are generated. - pilot_pool: list[Pilot] - - current_roster: list[Pilot] = field(default_factory=list, init=False, hash=False) - available_pilots: list[Pilot] = field( - default_factory=list, init=False, hash=False, compare=False - ) - - coalition: Coalition = field(hash=False, compare=False) - flight_db: Database[Flight] = field(hash=False, compare=False) - settings: Settings = field(hash=False, compare=False) - - location: ControlPoint - destination: Optional[ControlPoint] = field( - init=False, hash=False, compare=False, default=None - ) - - owned_aircraft: int = field(init=False, hash=False, compare=False, default=0) - untasked_aircraft: int = field(init=False, hash=False, compare=False, default=0) - pending_deliveries: int = field(init=False, hash=False, compare=False, default=0) - - def __str__(self) -> str: - if self.nickname is None: - return self.name - return f'{self.name} "{self.nickname}"' - - def __hash__(self) -> int: - return hash(self.id) - - def __eq__(self, other: object) -> bool: - if not isinstance(other, Squadron): - return False - return self.id == other.id - - @property - def player(self) -> bool: - return self.coalition.player - - def assign_to_base(self, base: ControlPoint) -> None: - self.location = base - logging.debug(f"Assigned {self} to {base}") - - @property - def pilot_limits_enabled(self) -> bool: - return self.settings.enable_squadron_pilot_limits - - def set_auto_assignable_mission_types( - self, mission_types: Iterable[FlightType] - ) -> None: - self.auto_assignable_mission_types = { - t for t in mission_types if self.capable_of(t) - } - - def claim_new_pilot_if_allowed(self) -> Optional[Pilot]: - if self.pilot_limits_enabled: - return None - self._recruit_pilots(1) - return self.available_pilots.pop() - - def claim_available_pilot(self) -> Optional[Pilot]: - if not self.available_pilots: - return self.claim_new_pilot_if_allowed() - - # For opfor, so player/AI option is irrelevant. - if not self.player: - return self.available_pilots.pop() - - preference = self.settings.auto_ato_behavior - - # No preference, so the first pilot is fine. - if preference is AutoAtoBehavior.Default: - return self.available_pilots.pop() - - prefer_players = preference is AutoAtoBehavior.Prefer - for pilot in self.available_pilots: - if pilot.player == prefer_players: - self.available_pilots.remove(pilot) - return pilot - - # No pilot was found that matched the user's preference. - # - # If they chose to *never* assign players and only players remain in the pool, - # we cannot fill the slot with the available pilots. - # - # If they only *prefer* players and we're out of players, just return an AI - # pilot. - if not prefer_players: - return self.claim_new_pilot_if_allowed() - return self.available_pilots.pop() - - def claim_pilot(self, pilot: Pilot) -> None: - if pilot not in self.available_pilots: - raise ValueError( - f"Cannot assign {pilot} to {self} because they are not available" - ) - self.available_pilots.remove(pilot) - - def return_pilot(self, pilot: Pilot) -> None: - self.available_pilots.append(pilot) - - def return_pilots(self, pilots: Sequence[Pilot]) -> None: - # Return in reverse so that returning two pilots and then getting two more - # results in the same ordering. This happens commonly when resetting rosters in - # the UI, when we clear the roster because the UI is updating, then end up - # repopulating the same size flight from the same squadron. - self.available_pilots.extend(reversed(pilots)) - - def _recruit_pilots(self, count: int) -> None: - new_pilots = self.pilot_pool[:count] - self.pilot_pool = self.pilot_pool[count:] - count -= len(new_pilots) - for _ in range(count): - if random.randint(1, 100) > self.female_pilot_percentage: - new_pilots.append(Pilot(self.faker.name_male())) - else: - new_pilots.append(Pilot(self.faker.name_female())) - self.current_roster.extend(new_pilots) - self.available_pilots.extend(new_pilots) - - def populate_for_turn_0(self) -> None: - if any(p.status is not PilotStatus.Active for p in self.pilot_pool): - raise ValueError("Squadrons can only be created with active pilots.") - self._recruit_pilots(self.settings.squadron_pilot_limit) - self.owned_aircraft = self.max_size - - def end_turn(self) -> None: - if self.destination is not None: - self.relocate_to(self.destination) - self.replenish_lost_pilots() - self.deliver_orders() - - def replenish_lost_pilots(self) -> None: - if self.pilot_limits_enabled and self.replenish_count > 0: - self._recruit_pilots(self.replenish_count) - - def return_all_pilots_and_aircraft(self) -> None: - self.available_pilots = list(self.active_pilots) - self.untasked_aircraft = self.owned_aircraft - - @staticmethod - def send_on_leave(pilot: Pilot) -> None: - pilot.send_on_leave() - - def return_from_leave(self, pilot: Pilot) -> None: - if not self.has_unfilled_pilot_slots: - raise RuntimeError( - f"Cannot return {pilot} from leave because {self} is full" - ) - pilot.return_from_leave() - - @property - def faker(self) -> Faker: - return self.coalition.faker - - def _pilots_with_status(self, status: PilotStatus) -> list[Pilot]: - return [p for p in self.current_roster if p.status == status] - - def _pilots_without_status(self, status: PilotStatus) -> list[Pilot]: - return [p for p in self.current_roster if p.status != status] - - @property - def pilot_limit(self) -> int: - return self.settings.squadron_pilot_limit - - @property - def expected_pilots_next_turn(self) -> int: - return len(self.active_pilots) + self.replenish_count - - @property - def replenish_count(self) -> int: - return min( - self.settings.squadron_replenishment_rate, - self._number_of_unfilled_pilot_slots, - ) - - @property - def active_pilots(self) -> list[Pilot]: - return self._pilots_with_status(PilotStatus.Active) - - @property - def pilots_on_leave(self) -> list[Pilot]: - return self._pilots_with_status(PilotStatus.OnLeave) - - @property - def number_of_pilots_including_inactive(self) -> int: - return len(self.current_roster) - - @property - def _number_of_unfilled_pilot_slots(self) -> int: - return self.pilot_limit - len(self.active_pilots) - - @property - def number_of_available_pilots(self) -> int: - return len(self.available_pilots) - - def can_provide_pilots(self, count: int) -> bool: - return not self.pilot_limits_enabled or self.number_of_available_pilots >= count - - @property - def has_available_pilots(self) -> bool: - return not self.pilot_limits_enabled or bool(self.available_pilots) - - @property - def has_unfilled_pilot_slots(self) -> bool: - return not self.pilot_limits_enabled or self._number_of_unfilled_pilot_slots > 0 - - def capable_of(self, task: FlightType) -> bool: - """Returns True if the squadron is capable of performing the given task. - - A squadron may be capable of performing a task even if it will not be - automatically assigned to it. - """ - return self.aircraft.capable_of(task) - - def can_auto_assign(self, task: FlightType) -> bool: - """Returns True if the squadron may be automatically assigned the given task. - - A squadron may be capable of performing a task even if it will not be - automatically assigned to it. - """ - return task in self.auto_assignable_mission_types - - def can_auto_assign_mission( - self, location: MissionTarget, task: FlightType, size: int, this_turn: bool - ) -> bool: - if not self.can_auto_assign(task): - return False - if this_turn and not self.can_fulfill_flight(size): - return False - - distance_to_target = meters(location.distance_to(self.location)) - return distance_to_target <= self.aircraft.max_mission_range - - def operates_from(self, control_point: ControlPoint) -> bool: - if not control_point.can_operate(self.aircraft): - return False - if control_point.is_carrier: - return self.operating_bases.carrier - elif control_point.is_lha: - return self.operating_bases.lha - else: - return self.operating_bases.shore - - def pilot_at_index(self, index: int) -> Pilot: - return self.current_roster[index] - - def claim_inventory(self, count: int) -> None: - if self.untasked_aircraft < count: - raise ValueError( - f"Cannot remove {count} from {self.name}. Only have " - f"{self.untasked_aircraft}." - ) - self.untasked_aircraft -= count - - def can_fulfill_flight(self, count: int) -> bool: - return self.can_provide_pilots(count) and self.untasked_aircraft >= count - - def refund_orders(self, count: Optional[int] = None) -> None: - if count is None: - count = self.pending_deliveries - self.coalition.adjust_budget(self.aircraft.price * count) - self.pending_deliveries -= count - - def deliver_orders(self) -> None: - self.cancel_overflow_orders() - self.owned_aircraft += self.pending_deliveries - self.pending_deliveries = 0 - - def relocate_to(self, destination: ControlPoint) -> None: - self.location = destination - if self.location == self.destination: - self.destination = None - - def cancel_overflow_orders(self) -> None: - if self.pending_deliveries <= 0: - return - overflow = -self.location.unclaimed_parking() - if overflow > 0: - sell_count = min(overflow, self.pending_deliveries) - logging.debug( - f"{self.location} is overfull by {overflow} aircraft. Cancelling " - f"orders for {sell_count} aircraft to make room." - ) - self.refund_orders(sell_count) - - @property - def max_fulfillable_aircraft(self) -> int: - return max(self.number_of_available_pilots, self.untasked_aircraft) - - @property - def expected_size_next_turn(self) -> int: - return self.owned_aircraft + self.pending_deliveries - - def has_aircraft_capacity_for(self, n: int) -> bool: - remaining = self.max_size - self.owned_aircraft - self.pending_deliveries - return remaining >= n - - @property - def arrival(self) -> ControlPoint: - return self.location if self.destination is None else self.destination - - def plan_relocation(self, destination: ControlPoint, now: datetime) -> None: - if destination == self.location: - logging.warning( - f"Attempted to plan relocation of {self} to current location " - f"{destination}. Ignoring." - ) - return - if destination == self.destination: - logging.warning( - f"Attempted to plan relocation of {self} to current destination " - f"{destination}. Ignoring." - ) - return - - if self.expected_size_next_turn > destination.unclaimed_parking(): - raise RuntimeError(f"Not enough parking for {self} at {destination}.") - if not destination.can_operate(self.aircraft): - raise RuntimeError(f"{self} cannot operate at {destination}.") - self.destination = destination - self.replan_ferry_flights(now) - - def cancel_relocation(self) -> None: - if self.destination is None: - logging.warning( - f"Attempted to cancel relocation of squadron with no transfer order. " - "Ignoring." - ) - return - - if self.expected_size_next_turn > self.location.unclaimed_parking(): - raise RuntimeError(f"Not enough parking for {self} at {self.location}.") - self.destination = None - self.cancel_ferry_flights() - - def replan_ferry_flights(self, now: datetime) -> None: - self.cancel_ferry_flights() - self.plan_ferry_flights(now) - - def cancel_ferry_flights(self) -> None: - for package in self.coalition.ato.packages: - # Copy the list so our iterator remains consistent throughout the removal. - for flight in list(package.flights): - if flight.squadron == self and flight.flight_type is FlightType.FERRY: - package.remove_flight(flight) - if not package.flights: - self.coalition.ato.remove_package(package) - - def plan_ferry_flights(self, now: datetime) -> None: - if self.destination is None: - raise RuntimeError( - f"Cannot plan ferry flights for {self} because there is no destination." - ) - remaining = self.untasked_aircraft - if not remaining: - return - - package = Package(self.destination, self.flight_db) - while remaining: - size = min(remaining, self.aircraft.max_group_size) - self.plan_ferry_flight(package, size) - remaining -= size - package.set_tot_asap(now) - self.coalition.ato.add_package(package) - - def plan_ferry_flight(self, package: Package, size: int) -> None: - start_type = self.location.required_aircraft_start_type - if start_type is None: - start_type = self.settings.default_start_type - - flight = Flight( - package, - self.coalition.country_name, - self, - size, - FlightType.FERRY, - start_type, - divert=None, - ) - package.add_flight(flight) - flight.recreate_flight_plan() - - @classmethod - def create_from( - cls, - squadron_def: SquadronDef, - primary_task: FlightType, - max_size: int, - base: ControlPoint, - coalition: Coalition, - game: Game, - ) -> Squadron: - squadron_def.claimed = True - return Squadron( - squadron_def.name, - squadron_def.nickname, - squadron_def.country, - squadron_def.role, - squadron_def.aircraft, - max_size, - squadron_def.livery, - primary_task, - squadron_def.auto_assignable_mission_types, - squadron_def.operating_bases, - squadron_def.female_pilot_percentage, - squadron_def.pilot_pool, - coalition, - game.db.flights, - game.settings, - base, - ) diff --git a/game/squadrons/squadrondef.py b/game/squadrons/squadrondef.py deleted file mode 100644 index 22d5b99b9..000000000 --- a/game/squadrons/squadrondef.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from pathlib import Path -from typing import Optional, TYPE_CHECKING - -import yaml - -from game.dcs.aircrafttype import AircraftType -from game.squadrons.operatingbases import OperatingBases -from game.squadrons.pilot import Pilot - -if TYPE_CHECKING: - from game.ato.flighttype import FlightType - from game.theater import ControlPoint - - -@dataclass -class SquadronDef: - name: str - nickname: Optional[str] - country: str - role: str - aircraft: AircraftType - livery: Optional[str] - auto_assignable_mission_types: set[FlightType] - operating_bases: OperatingBases - female_pilot_percentage: int - pilot_pool: list[Pilot] - claimed: bool = False - - def __str__(self) -> str: - if self.nickname is None: - return self.name - return f'{self.name} "{self.nickname}"' - - def capable_of(self, task: FlightType) -> bool: - """Returns True if the squadron is capable of performing the given task. - - A squadron may be capable of performing a task even if it will not be - automatically assigned to it. - """ - return self.aircraft.capable_of(task) - - def operates_from(self, control_point: ControlPoint) -> bool: - if not control_point.can_operate(self.aircraft): - return False - if control_point.is_carrier: - return self.operating_bases.carrier - elif control_point.is_lha: - return self.operating_bases.lha - else: - return self.operating_bases.shore - - @classmethod - def from_yaml(cls, path: Path) -> SquadronDef: - with path.open(encoding="utf8") as squadron_file: - data = yaml.safe_load(squadron_file) - - name = data["aircraft"] - try: - unit_type = AircraftType.named(name) - except KeyError as ex: - raise KeyError(f"Could not find any aircraft named {name}") from ex - - pilots = [Pilot(n, player=False) for n in data.get("pilots", [])] - pilots.extend([Pilot(n, player=True) for n in data.get("players", [])]) - female_pilot_percentage = data.get("female_pilot_percentage", 6) - - return SquadronDef( - name=data["name"], - nickname=data.get("nickname"), - country=data["country"], - role=data["role"], - aircraft=unit_type, - livery=data.get("livery"), - auto_assignable_mission_types=set(unit_type.iter_task_capabilities()), - operating_bases=OperatingBases.from_yaml(unit_type, data.get("bases", {})), - female_pilot_percentage=female_pilot_percentage, - pilot_pool=pilots, - ) diff --git a/game/squadrons/squadrondefloader.py b/game/squadrons/squadrondefloader.py deleted file mode 100644 index cfd1197ee..000000000 --- a/game/squadrons/squadrondefloader.py +++ /dev/null @@ -1,68 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from pathlib import Path -from typing import Iterator, TYPE_CHECKING, Tuple - -from game.dcs.aircrafttype import AircraftType -from .squadrondef import SquadronDef - -if TYPE_CHECKING: - from game import Game - from ..factions.faction import Faction - - -class SquadronDefLoader: - def __init__(self, game: Game, faction: Faction) -> None: - self.game = game - self.faction = faction - - @staticmethod - def squadron_directories() -> Iterator[Path]: - from game import persistence - - yield Path(persistence.base_path()) / "Liberation/Squadrons" - yield Path("resources/squadrons") - - def load(self) -> dict[AircraftType, list[SquadronDef]]: - squadrons: dict[AircraftType, list[SquadronDef]] = defaultdict(list) - country = self.faction.country - faction = self.faction - any_country = country.startswith("Combined Joint Task Forces ") - for directory in self.squadron_directories(): - for path, squadron_def in self.load_squadrons_from(directory): - if not any_country and squadron_def.country != country: - logging.debug( - "Not using squadron for non-matching country (is " - f"{squadron_def.country}, need {country}: {path}" - ) - continue - if squadron_def.aircraft not in faction.aircrafts: - logging.debug( - f"Not using squadron because {faction.name} cannot use " - f"{squadron_def.aircraft}: {path}" - ) - continue - logging.debug( - f"Found {squadron_def.name} {squadron_def.aircraft} " - f"{squadron_def.role} compatible with {faction.name}" - ) - - squadrons[squadron_def.aircraft].append(squadron_def) - return squadrons - - @staticmethod - def load_squadrons_from(directory: Path) -> Iterator[Tuple[Path, SquadronDef]]: - logging.debug(f"Looking for factions in {directory}") - # First directory level is the aircraft type so that historical squadrons that - # have flown multiple airframes can be defined as many times as needed. The main - # load() method is responsible for filtering out squadrons that aren't - # compatible with the faction. - for squadron_path in directory.glob("*/*.yaml"): - try: - yield squadron_path, SquadronDef.from_yaml(squadron_path) - except Exception as ex: - raise RuntimeError( - f"Failed to load squadron defined by {squadron_path}" - ) from ex diff --git a/game/theater/__init__.py b/game/theater/__init__.py deleted file mode 100644 index d741edb70..000000000 --- a/game/theater/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .base import * -from .conflicttheater import * -from .controlpoint import * -from .frontline import FrontLine -from .missiontarget import MissionTarget -from .theatergroundobject import SamGroundObject diff --git a/game/theater/base.py b/game/theater/base.py deleted file mode 100644 index a4d7568b5..000000000 --- a/game/theater/base.py +++ /dev/null @@ -1,50 +0,0 @@ -from game.dcs.groundunittype import GroundUnitType - -BASE_MAX_STRENGTH = 1.0 -BASE_MIN_STRENGTH = 0.0 - - -class Base: - def __init__(self) -> None: - self.armor: dict[GroundUnitType, int] = {} - self.strength = 1.0 - - @property - def total_armor(self) -> int: - return sum(self.armor.values()) - - @property - def total_armor_value(self) -> int: - total = 0 - for unit_type, count in self.armor.items(): - total += unit_type.price * count - return total - - def total_units_of_type(self, unit_type: GroundUnitType) -> int: - return sum([c for t, c in self.armor.items() if t == unit_type]) - - def commission_units(self, units: dict[GroundUnitType, int]) -> None: - for unit_type, unit_count in units.items(): - if unit_count <= 0: - continue - self.armor[unit_type] = self.armor.get(unit_type, 0) + unit_count - - def commit_losses(self, units_lost: dict[GroundUnitType, int]) -> None: - for unit_type, count in units_lost.items(): - if unit_type not in self.armor: - print("Base didn't find unit type {}".format(unit_type)) - continue - - self.armor[unit_type] = max(self.armor[unit_type] - count, 0) - if self.armor[unit_type] == 0: - del self.armor[unit_type] - - def affect_strength(self, amount: float) -> None: - self.strength += amount - if self.strength > BASE_MAX_STRENGTH: - self.strength = BASE_MAX_STRENGTH - elif self.strength <= 0: - self.strength = BASE_MIN_STRENGTH - - def set_strength_to_minimum(self) -> None: - self.strength = BASE_MIN_STRENGTH diff --git a/game/theater/bullseye.py b/game/theater/bullseye.py deleted file mode 100644 index 2c1aeaf62..000000000 --- a/game/theater/bullseye.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Dict - -from dcs import Point - - -@dataclass -class Bullseye: - position: Point - - def to_pydcs(self) -> Dict[str, float]: - return {"x": self.position.x, "y": self.position.y} diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py deleted file mode 100644 index 7575daed9..000000000 --- a/game/theater/conflicttheater.py +++ /dev/null @@ -1,236 +0,0 @@ -from __future__ import annotations - -import math -from datetime import timezone -from typing import Iterator, List, Optional, TYPE_CHECKING, Tuple -from uuid import UUID - -from dcs.mapping import Point -from dcs.terrain.terrain import Terrain -from shapely import geometry, ops - -from .daytimemap import DaytimeMap -from .frontline import FrontLine -from .iadsnetwork.iadsnetwork import IadsNetwork -from .landmap import Landmap, poly_contains -from .seasonalconditions import SeasonalConditions -from ..utils import Heading - -if TYPE_CHECKING: - from .controlpoint import ControlPoint, MissionTarget - from .theatergroundobject import TheaterGroundObject - - -class ConflictTheater: - iads_network: IadsNetwork - - def __init__( - self, - terrain: Terrain, - landmap: Landmap | None, - time_zone: timezone, - seasonal_conditions: SeasonalConditions, - daytime_map: DaytimeMap, - ) -> None: - self.terrain = terrain - self.landmap = landmap - self.timezone = time_zone - self.seasonal_conditions = seasonal_conditions - self.daytime_map = daytime_map - self.controlpoints: list[ControlPoint] = [] - - def add_controlpoint(self, point: ControlPoint) -> None: - self.controlpoints.append(point) - - @property - def ground_objects(self) -> Iterator[TheaterGroundObject]: - for cp in self.controlpoints: - for go in cp.ground_objects: - yield go - - def find_ground_objects_by_obj_name( - self, obj_name: str - ) -> list[TheaterGroundObject]: - found = [] - for cp in self.controlpoints: - for g in cp.ground_objects: - if g.obj_name == obj_name: - found.append(g) - return found - - def is_in_sea(self, point: Point) -> bool: - if not self.landmap: - return False - - if self.is_on_land(point): - return False - - for exclusion_zone in self.landmap.exclusion_zones.geoms: - if poly_contains(point.x, point.y, exclusion_zone): - return False - - for sea in self.landmap.sea_zones.geoms: - if poly_contains(point.x, point.y, sea): - return True - - return False - - def is_on_land(self, point: Point) -> bool: - if not self.landmap: - return True - - is_point_included = False - if poly_contains(point.x, point.y, self.landmap.inclusion_zones): - is_point_included = True - - if not is_point_included: - return False - - for exclusion_zone in self.landmap.exclusion_zones.geoms: - if poly_contains(point.x, point.y, exclusion_zone): - return False - - return True - - def nearest_land_pos(self, near: Point, extend_dist: int = 50) -> Point: - """Returns the nearest point inside a land exclusion zone from point - `extend_dist` determines how far inside the zone the point should be placed""" - if self.is_on_land(near): - return near - point = geometry.Point(near.x, near.y) - nearest_points = [] - if not self.landmap: - raise RuntimeError("Landmap not initialized") - for inclusion_zone in self.landmap.inclusion_zones.geoms: - nearest_pair = ops.nearest_points(point, inclusion_zone) - nearest_points.append(nearest_pair[1]) - min_distance = point.distance(nearest_points[0]) # type: geometry.Point - nearest_point = nearest_points[0] # type: geometry.Point - for pt in nearest_points[1:]: - distance = point.distance(pt) - if distance < min_distance: - min_distance = distance - nearest_point = pt - assert isinstance(nearest_point, geometry.Point) - point = Point(point.x, point.y, self.terrain) - nearest_point = Point(nearest_point.x, nearest_point.y, self.terrain) - new_point = point.point_from_heading( - point.heading_between_point(nearest_point), - point.distance_to_point(nearest_point) + extend_dist, - ) - return new_point - - def control_points_for(self, player: bool) -> Iterator[ControlPoint]: - for point in self.controlpoints: - if point.captured == player: - yield point - - def player_points(self) -> List[ControlPoint]: - return list(self.control_points_for(player=True)) - - def conflicts(self) -> Iterator[FrontLine]: - for cp in self.player_points(): - yield from cp.front_lines.values() - - def enemy_points(self) -> List[ControlPoint]: - return list(self.control_points_for(player=False)) - - def closest_control_point( - self, point: Point, allow_naval: bool = False - ) -> ControlPoint: - closest = self.controlpoints[0] - closest_distance = point.distance_to_point(closest.position) - for control_point in self.controlpoints[1:]: - if control_point.is_fleet and not allow_naval: - continue - distance = point.distance_to_point(control_point.position) - if distance < closest_distance: - closest = control_point - closest_distance = distance - return closest - - def closest_target(self, point: Point) -> MissionTarget: - closest: MissionTarget = self.controlpoints[0] - closest_distance = point.distance_to_point(closest.position) - for control_point in self.controlpoints[1:]: - distance = point.distance_to_point(control_point.position) - if distance < closest_distance: - closest = control_point - closest_distance = distance - for tgo in control_point.ground_objects: - distance = point.distance_to_point(tgo.position) - if distance < closest_distance: - closest = tgo - closest_distance = distance - for conflict in self.conflicts(): - distance = conflict.position.distance_to_point(point) - if distance < closest_distance: - closest = conflict - closest_distance = distance - return closest - - def closest_opposing_control_points(self) -> Tuple[ControlPoint, ControlPoint]: - """ - Returns a tuple of the two nearest opposing ControlPoints in theater. - (player_cp, enemy_cp) - """ - seen = set() - min_distance = math.inf - closest_blue = None - closest_red = None - for blue_cp in self.player_points(): - for red_cp in self.enemy_points(): - if (blue_cp, red_cp) in seen: - continue - seen.add((blue_cp, red_cp)) - seen.add((red_cp, blue_cp)) - - dist = red_cp.position.distance_to_point(blue_cp.position) - if dist < min_distance: - closest_red = red_cp - closest_blue = blue_cp - min_distance = dist - - assert closest_blue is not None - assert closest_red is not None - return closest_blue, closest_red - - def find_control_point_by_id(self, cp_id: UUID) -> ControlPoint: - for i in self.controlpoints: - if i.id == cp_id: - return i - raise KeyError(f"Cannot find ControlPoint with ID {cp_id}") - - def find_control_point_by_airport_id(self, airport_id: int) -> ControlPoint: - for cp in self.controlpoints: - if cp.dcs_airport is not None and cp.dcs_airport.id == airport_id: - return cp - raise KeyError(f"Cannot find ControlPoint with airport ID {airport_id}") - - def control_point_named(self, name: str) -> ControlPoint: - for cp in self.controlpoints: - if cp.name == name: - return cp - raise KeyError(f"Cannot find ControlPoint named {name}") - - def heading_to_conflict_from(self, position: Point) -> Optional[Heading]: - # Heading for a Group to the enemy. - # Should be the point between the nearest and the most distant conflict - conflicts: dict[MissionTarget, float] = {} - - for conflict in self.conflicts(): - conflicts[conflict] = conflict.position.distance_to_point(position) - - if len(conflicts) == 0: - return None - - sorted_conflicts = [ - k for k, v in sorted(conflicts.items(), key=lambda item: item[1]) - ] - last = len(sorted_conflicts) - 1 - - conflict_center = sorted_conflicts[0].position.midpoint( - sorted_conflicts[last].position - ) - - return Heading.from_degrees(position.heading_between_point(conflict_center)) diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py deleted file mode 100644 index 2b71df9ab..000000000 --- a/game/theater/controlpoint.py +++ /dev/null @@ -1,1534 +0,0 @@ -from __future__ import annotations - -import heapq -import itertools -import logging -import math -import uuid -from abc import ABC, abstractmethod -from collections import defaultdict -from dataclasses import dataclass, field -from enum import Enum, IntEnum, auto, unique -from functools import cached_property, total_ordering -from typing import ( - Any, - Dict, - Iterable, - Iterator, - List, - Optional, - Sequence, - Set, - TYPE_CHECKING, - Tuple, - Type, -) -from uuid import UUID - -from dcs.mapping import Point -from dcs.ships import ( - Ara_vdm, - CVN_71, - CVN_72, - CVN_73, - CVN_75, - CV_1143_5, - Forrestal, - Hms_invincible, - KUZNECOW, - LHA_Tarawa, - Stennis, - Type_071, -) -from dcs.terrain.terrain import Airport, ParkingSlot -from dcs.unitgroup import ShipGroup, StaticGroup -from dcs.unittype import ShipType - -from game.ato.closestairfields import ObjectiveDistanceCache -from game.ground_forces.combat_stance import CombatStance -from game.point_with_heading import PointWithHeading -from game.runways import RunwayAssigner, RunwayData -from game.scenery_group import SceneryGroup -from game.sidc import ( - Entity, - LandInstallationEntity, - SeaSurfaceEntity, - SidcDescribable, - StandardIdentity, - Status, - SymbolSet, -) -from game.theater.presetlocation import PresetLocation -from game.utils import Distance, Heading, meters -from .base import Base -from .frontline import FrontLine -from .missiontarget import MissionTarget -from .theatergroundobject import ( - GenericCarrierGroundObject, - IadsGroundObject, - TheaterGroundObject, - VehicleGroupGroundObject, -) -from .theatergroup import TheaterUnit -from ..ato.starttype import StartType -from ..data.units import UnitClass -from ..db import Database -from ..dcs.aircrafttype import AircraftType -from ..dcs.groundunittype import GroundUnitType -from ..utils import nautical_miles -from ..weather.conditions import Conditions - -if TYPE_CHECKING: - from game import Game - from game.ato.flighttype import FlightType - from game.coalition import Coalition - from game.lasercodes.lasercoderegistry import LaserCodeRegistry - from game.sim import GameUpdateEvents - from game.squadrons.squadron import Squadron - from game.transfers import PendingTransfers - from .conflicttheater import ConflictTheater - -FREE_FRONTLINE_UNIT_SUPPLY: int = 15 -AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION: int = 12 - - -class ControlPointType(Enum): - #: An airbase with slots for everything. - AIRBASE = 0 - #: A group with a Stennis type carrier (F/A-18, F-14 compatible). - AIRCRAFT_CARRIER_GROUP = 1 - #: A group with a Tarawa carrier (Helicopters & Harrier). - LHA_GROUP = 2 - #: A FARP, with slots for helicopters - FARP = 4 - #: A FOB (ground units only) - FOB = 5 - OFF_MAP = 6 - - -@dataclass -class PresetLocations: - """Defines the preset locations loaded from the campaign mission file.""" - - #: Locations used by non-carrier ships that will be spawned unless the faction has - #: no navy or the player has disabled ship generation for the owning side. - ships: List[PresetLocation] = field(default_factory=list) - - #: Locations used by coastal defenses that are generated if the faction is capable. - coastal_defenses: List[PresetLocation] = field(default_factory=list) - - #: Locations used by ground based strike objectives. - strike_locations: List[PresetLocation] = field(default_factory=list) - - #: Locations used by offshore strike objectives. - offshore_strike_locations: List[PresetLocation] = field(default_factory=list) - - #: Locations used by missile sites like scuds and V-2s that are generated if the - #: faction is capable. - missile_sites: List[PresetLocation] = field(default_factory=list) - - #: Locations of long range SAMs. - long_range_sams: List[PresetLocation] = field(default_factory=list) - - #: Locations of medium range SAMs. - medium_range_sams: List[PresetLocation] = field(default_factory=list) - - #: Locations of short range SAMs. - short_range_sams: List[PresetLocation] = field(default_factory=list) - - #: Locations of AAA groups. - aaa: List[PresetLocation] = field(default_factory=list) - - #: Locations of EWRs. - ewrs: List[PresetLocation] = field(default_factory=list) - - #: Locations of map scenery to create zones for. - scenery: List[SceneryGroup] = field(default_factory=list) - - #: Locations of factories for producing ground units. - factories: List[PresetLocation] = field(default_factory=list) - - #: Locations of ammo depots for controlling number of units on the front line at a - #: control point. - ammunition_depots: List[PresetLocation] = field(default_factory=list) - - #: Locations of stationary armor groups. - armor_groups: List[PresetLocation] = field(default_factory=list) - - #: Locations of skynet specific groups - iads_connection_node: List[PresetLocation] = field(default_factory=list) - iads_power_source: List[PresetLocation] = field(default_factory=list) - iads_command_center: List[PresetLocation] = field(default_factory=list) - - -@dataclass(frozen=True) -class AircraftAllocations: - present: dict[AircraftType, int] - ordered: dict[AircraftType, int] - transferring: dict[AircraftType, int] - - @property - def total_value(self) -> int: - total: int = 0 - for unit_type, count in self.present.items(): - total += unit_type.price * count - for unit_type, count in self.ordered.items(): - total += unit_type.price * count - for unit_type, count in self.transferring.items(): - total += unit_type.price * count - - return total - - @property - def total(self) -> int: - return self.total_present + self.total_ordered + self.total_transferring - - @property - def total_present(self) -> int: - return sum(self.present.values()) - - @property - def total_ordered(self) -> int: - return sum(self.ordered.values()) - - @property - def total_transferring(self) -> int: - return sum(self.transferring.values()) - - -@dataclass(frozen=True) -class GroundUnitAllocations: - present: dict[GroundUnitType, int] - ordered: dict[GroundUnitType, int] - transferring: dict[GroundUnitType, int] - - @property - def all(self) -> dict[GroundUnitType, int]: - combined: dict[GroundUnitType, int] = defaultdict(int) - for unit_type, count in itertools.chain( - self.present.items(), self.ordered.items(), self.transferring.items() - ): - combined[unit_type] += count - return dict(combined) - - @property - def total_value(self) -> int: - total: int = 0 - for unit_type, count in self.present.items(): - total += unit_type.price * count - for unit_type, count in self.ordered.items(): - total += unit_type.price * count - for unit_type, count in self.transferring.items(): - total += unit_type.price * count - - return total - - @cached_property - def total(self) -> int: - return self.total_present + self.total_ordered + self.total_transferring - - @cached_property - def total_present(self) -> int: - return sum(self.present.values()) - - @cached_property - def total_ordered(self) -> int: - return sum(self.ordered.values()) - - @cached_property - def total_transferring(self) -> int: - return sum(self.transferring.values()) - - -@dataclass -class RunwayStatus: - damaged: bool = False - repair_turns_remaining: Optional[int] = None - - def damage(self) -> None: - self.damaged = True - # If the runway is already under repair and is damaged again, progress - # is reset. - self.repair_turns_remaining = None - - def repair(self) -> None: - self.repair_turns_remaining = None - self.damaged = False - - def begin_repair(self) -> None: - if self.repair_turns_remaining is not None: - logging.error("Runway already under repair. Restarting.") - self.repair_turns_remaining = 4 - - def process_turn(self) -> None: - if self.repair_turns_remaining is not None: - if self.repair_turns_remaining == 1: - self.repair() - else: - self.repair_turns_remaining -= 1 - - @property - def needs_repair(self) -> bool: - return self.damaged and self.repair_turns_remaining is None - - def describe(self) -> str: - if not self.damaged: - return "operational" - - turns_remaining = self.repair_turns_remaining - if turns_remaining is None: - return "damaged" - - return f"repairing, {turns_remaining} turns remaining" - - -@total_ordering -class GroundUnitDestination: - def __init__(self, control_point: ControlPoint) -> None: - self.control_point = control_point - - @property - def total_value(self) -> float: - return self.control_point.base.total_armor_value - - def __eq__(self, other: Any) -> bool: - if not isinstance(other, GroundUnitDestination): - raise TypeError - - return self.total_value == other.total_value - - def __lt__(self, other: Any) -> bool: - if not isinstance(other, GroundUnitDestination): - raise TypeError - - return self.total_value < other.total_value - - -@unique -class ControlPointStatus(IntEnum): - Functional = auto() - Damaged = auto() - Destroyed = auto() - - -StartingPosition = ShipGroup | StaticGroup | Airport | Point - - -class ControlPoint(MissionTarget, SidcDescribable, ABC): - # Not sure what distance DCS uses, but assuming it's about 2NM since that's roughly - # the distance of the circle on the map. - CAPTURE_DISTANCE = nautical_miles(2) - - # TODO: Only airbases have IDs. - # TODO: cptype is obsolete. - def __init__( - self, - name: str, - position: Point, - at: StartingPosition, - theater: ConflictTheater, - starts_blue: bool, - cptype: ControlPointType = ControlPointType.AIRBASE, - ) -> None: - super().__init__(name, position) - self.id = uuid.uuid4() - self.full_name = name - self.at = at - self.theater = theater - self.starts_blue = starts_blue - self.connected_objectives: List[TheaterGroundObject] = [] - self.preset_locations = PresetLocations() - self.helipads: List[PointWithHeading] = [] - - self._coalition: Optional[Coalition] = None - self.captured_invert = False - self.front_lines: dict[ControlPoint, FrontLine] = {} - # TODO: Should be Airbase specific. - self.connected_points: List[ControlPoint] = [] - self.convoy_routes: Dict[ControlPoint, Tuple[Point, ...]] = {} - self.shipping_lanes: Dict[ControlPoint, Tuple[Point, ...]] = {} - self.base: Base = Base() - self.cptype = cptype - # TODO: Should be Airbase specific. - self.stances: dict[UUID, CombatStance] = {} - from ..groundunitorders import GroundUnitOrders - - self.ground_unit_orders = GroundUnitOrders(self) - - self.target_position: Optional[Point] = None - self.ferry_only = False - - # Initialized late because ControlPoints are constructed before the game is. - self._front_line_db: Database[FrontLine] | None = None - - def __repr__(self) -> str: - return f"<{self.__class__}: {self.name}>" - - @property - def dcs_airport(self) -> Airport | None: - return None - - @property - def coalition(self) -> Coalition: - if self._coalition is None: - raise RuntimeError("ControlPoint not fully initialized: coalition not set") - return self._coalition - - def finish_init(self, game: Game) -> None: - assert self._coalition is None - self._coalition = game.coalition_for(self.starts_blue) - assert self._front_line_db is None - self._front_line_db = game.db.front_lines - - def initialize_turn_0(self, laser_code_registry: LaserCodeRegistry) -> None: - # We don't need to send events for turn 0. The UI isn't up yet, and it'll fetch - # the entire game state when it comes up. - from game.sim import GameUpdateEvents - - self._create_missing_front_lines(laser_code_registry, GameUpdateEvents()) - - @property - def front_line_db(self) -> Database[FrontLine]: - assert self._front_line_db is not None - return self._front_line_db - - def _create_missing_front_lines( - self, laser_code_registry: LaserCodeRegistry, events: GameUpdateEvents - ) -> None: - for connection in self.convoy_routes.keys(): - if not connection.front_line_active_with( - self - ) and not connection.is_friendly_to(self): - self._create_front_line_with(laser_code_registry, connection, events) - - def _create_front_line_with( - self, - laser_code_registry: LaserCodeRegistry, - connection: ControlPoint, - events: GameUpdateEvents, - ) -> None: - blue, red = FrontLine.sort_control_points(self, connection) - front = FrontLine(blue, red, laser_code_registry.alloc_laser_code()) - self.front_lines[connection] = front - connection.front_lines[self] = front - self.front_line_db.add(front.id, front) - events.update_front_line(front) - - def _remove_front_line_with( - self, - connection: ControlPoint, - events: GameUpdateEvents, - ) -> None: - front = self.front_lines[connection] - del self.front_lines[connection] - del connection.front_lines[self] - self.front_line_db.remove(front.id) - front.laser_code.release() - events.delete_front_line(front) - - def _clear_front_lines(self, events: GameUpdateEvents) -> None: - for opponent in list(self.front_lines.keys()): - self._remove_front_line_with(opponent, events) - - @property - def has_frontline(self) -> bool: - return bool(self.front_lines) - - def front_line_active_with(self, other: ControlPoint) -> bool: - return other in self.front_lines - - def front_line_with(self, other: ControlPoint) -> FrontLine: - return self.front_lines[other] - - @property - def captured(self) -> bool: - return self.coalition.player - - @property - def standard_identity(self) -> StandardIdentity: - return ( - StandardIdentity.FRIEND if self.captured else StandardIdentity.HOSTILE_FAKER - ) - - @property - def sidc_status(self) -> Status: - if self.status is ControlPointStatus.Functional: - return Status.PRESENT - if self.status is ControlPointStatus.Damaged: - return Status.PRESENT_DAMAGED - if self.status is ControlPointStatus.Destroyed: - return Status.PRESENT_DESTROYED - raise ValueError(f"Unexpected ControlPointStatus: {self.status}") - - @property - def ground_objects(self) -> List[TheaterGroundObject]: - return list(self.connected_objectives) - - @property - def squadrons(self) -> Iterator[Squadron]: - for squadron in self.coalition.air_wing.iter_squadrons(): - if squadron.location == self: - yield squadron - - @property - @abstractmethod - def heading(self) -> Heading: - ... - - def __str__(self) -> str: - return self.name - - @property - def is_isolated(self) -> bool: - return not self.connected_points - - @property - def is_global(self) -> bool: - return self.is_isolated - - def transitive_connected_friendly_points( - self, seen: Optional[Set[ControlPoint]] = None - ) -> List[ControlPoint]: - if seen is None: - seen = {self} - - connected = [] - for cp in self.connected_points: - if cp.captured != self.captured: - continue - if cp in seen: - continue - seen.add(cp) - connected.append(cp) - connected.extend(cp.transitive_connected_friendly_points(seen)) - return connected - - def transitive_friendly_shipping_destinations( - self, seen: Optional[Set[ControlPoint]] = None - ) -> List[ControlPoint]: - if seen is None: - seen = {self} - - connected = [] - for cp in self.shipping_lanes: - if cp.captured != self.captured: - continue - if cp in seen: - continue - seen.add(cp) - connected.append(cp) - connected.extend(cp.transitive_friendly_shipping_destinations(seen)) - return connected - - @property - def has_factory(self) -> bool: - for tgo in self.connected_objectives: - if tgo.is_factory and not tgo.is_dead: - return True - return False - - @property - def has_helipads(self) -> bool: - """ - Returns true if cp has helipads - """ - return len(self.helipads) > 0 - - def can_recruit_ground_units(self, game: Game) -> bool: - """Returns True if this control point is capable of recruiting ground units.""" - if not self.can_deploy_ground_units: - return False - - if game.turn == 0: - # Allow units to be recruited anywhere on turn 0 to avoid long delays to get - # everyone to the front line. - return True - - return self.has_factory - - def has_ground_unit_source(self, game: Game) -> bool: - """Returns True if this control point has access to ground reinforcements.""" - if not self.can_deploy_ground_units: - return False - - for cp in game.theater.controlpoints: - if cp.is_friendly(self.captured) and cp.can_recruit_ground_units(game): - return True - return False - - @property - def is_carrier(self) -> bool: - """ - :return: Whether this control point is an aircraft carrier - """ - return False - - @property - def is_fleet(self) -> bool: - """ - :return: Whether this control point is a boat (mobile) - """ - return False - - @property - def is_lha(self) -> bool: - """ - :return: Whether this control point is an LHA - """ - return False - - @property - def moveable(self) -> bool: - """ - :return: Whether this control point can be moved around - """ - return self.max_move_distance > meters(0) - - @property - def max_move_distance(self) -> Distance: - return meters(0) - - def destination_in_range(self, destination: Point) -> bool: - distance = meters(destination.distance_to_point(self.position)) - return distance <= self.max_move_distance - - @property - @abstractmethod - def can_deploy_ground_units(self) -> bool: - ... - - @property - @abstractmethod - def total_aircraft_parking(self) -> int: - """ - :return: The maximum number of aircraft that can be stored in this - control point - """ - ... - - def convoy_origin_for(self, destination: ControlPoint) -> Point: - return self.convoy_route_to(destination)[0] - - def convoy_route_to(self, destination: ControlPoint) -> Sequence[Point]: - return self.convoy_routes[destination] - - def create_convoy_route(self, to: ControlPoint, waypoints: Iterable[Point]) -> None: - self.connected_points.append(to) - self.stances[to.id] = CombatStance.DEFENSIVE - self.convoy_routes[to] = tuple(waypoints) - - def create_shipping_lane( - self, to: ControlPoint, waypoints: Iterable[Point] - ) -> None: - self.shipping_lanes[to] = tuple(waypoints) - - @abstractmethod - def runway_is_operational(self) -> bool: - """ - Check whether this control point supports taking offs and landings. - :return: - """ - ... - - # TODO: Should be naval specific. - def get_carrier_group_name(self) -> Optional[str]: - """ - Get the carrier group name if the airbase is a carrier - :return: Carrier group name - """ - if self.cptype in [ - ControlPointType.AIRCRAFT_CARRIER_GROUP, - ControlPointType.LHA_GROUP, - ]: - for g in self.ground_objects: - for group in g.groups: - for u in group.units: - if u.unit_type and u.unit_type.unit_class in [ - UnitClass.AIRCRAFT_CARRIER, - UnitClass.HELICOPTER_CARRIER, - ]: - return group.group_name - return None - - def get_carrier_group_type( - self, always_supercarrier: bool = False - ) -> Optional[Type[ShipType]]: - """ - Get the carrier group type if the airbase is a carrier. Arguments: - always_supercarrier: True if should always return the supercarrier type, False if should only - return the supercarrier type when the supercarrier option is enabled in settings. - :return: Carrier group type - """ - if self.cptype in [ - ControlPointType.AIRCRAFT_CARRIER_GROUP, - ControlPointType.LHA_GROUP, - ]: - for g in self.ground_objects: - for group in g.groups: - u = group.units[0] - carrier_type = u.type - if ( - u.unit_type - and u.unit_type.unit_class - in [ - UnitClass.AIRCRAFT_CARRIER, - UnitClass.HELICOPTER_CARRIER, - ] - and issubclass(carrier_type, ShipType) - ): - if ( - self.coalition.game.settings.supercarrier - or always_supercarrier - ): - return self.upgrade_to_supercarrier(carrier_type, self.name) - return carrier_type - return None - - @staticmethod - def upgrade_to_supercarrier(unit: Type[ShipType], name: str) -> Type[ShipType]: - if unit == Stennis: - if name == "CVN-71 Theodore Roosevelt": - return CVN_71 - elif name == "CVN-72 Abraham Lincoln": - return CVN_72 - elif name == "CVN-73 George Washington": - return CVN_73 - elif name == "CVN-75 Harry S. Truman": - return CVN_75 - elif name == "Carrier Strike Group 8": - return CVN_75 - else: - return CVN_71 - elif unit == KUZNECOW: - return CV_1143_5 - else: - return unit - - # TODO: Should be Airbase specific. - def is_connected(self, to: ControlPoint) -> bool: - return to in self.connected_points - - def find_ground_objects_by_obj_name( - self, obj_name: str - ) -> list[TheaterGroundObject]: - found = [] - for g in self.ground_objects: - if g.obj_name == obj_name: - found.append(g) - return found - - def is_friendly(self, to_player: bool) -> bool: - return self.captured == to_player - - def is_friendly_to(self, control_point: ControlPoint) -> bool: - return control_point.is_friendly(self.captured) - - def capture_equipment(self, game: Game) -> None: - total = self.base.total_armor_value - self.base.armor.clear() - game.adjust_budget(total, player=not self.captured) - game.message( - f"{self.name} is not connected to any friendly points. Ground " - f"vehicles have been captured and sold for ${total}M." - ) - - def retreat_ground_units(self, game: Game) -> None: - # When there are multiple valid destinations, deliver units to whichever - # base is least defended first. The closest approximation of unit - # strength we have is price - destinations = [ - GroundUnitDestination(cp) - for cp in self.connected_points - if cp.captured == self.captured - ] - if not destinations: - self.capture_equipment(game) - return - - heapq.heapify(destinations) - destination = heapq.heappop(destinations) - while self.base.armor: - unit_type, count = self.base.armor.popitem() - for _ in range(count): - destination.control_point.base.commission_units({unit_type: 1}) - destination = heapq.heappushpop(destinations, destination) - - def capture_aircraft(self, game: Game, airframe: AircraftType, count: int) -> None: - value = airframe.price * count - game.adjust_budget(value, player=not self.captured) - game.message( - f"No valid retreat destination in range of {self.name} for {airframe} " - f"{count} aircraft have been captured and sold for ${value}M." - ) - - def aircraft_retreat_destination( - self, squadron: Squadron - ) -> Optional[ControlPoint]: - closest = ObjectiveDistanceCache.get_closest_airfields(self) - max_retreat_distance = squadron.aircraft.max_mission_range - # Skip the first airbase because that's the airbase we're retreating - # from. - airfields = list(closest.operational_airfields_within(max_retreat_distance))[1:] - not_preferred: Optional[ControlPoint] = None - overfull: list[ControlPoint] = [] - for airbase in airfields: - if airbase.captured != self.captured: - continue - - if airbase.unclaimed_parking() < squadron.owned_aircraft: - if airbase.can_operate(squadron.aircraft): - overfull.append(airbase) - continue - - if squadron.operates_from(airbase): - # Has room, is a preferred base type for this squadron, and is the - # closest choice. No need to keep looking. - return airbase - - if not_preferred is None and airbase.can_operate(squadron.aircraft): - # Has room and is capable of operating from this base, but it isn't - # preferred. Remember this option and use it if we can't find a - # preferred base type with room. - not_preferred = airbase - if not_preferred is not None: - # It's not our best choice but the other choices don't have room for the - # squadron and would lead to aircraft being captured. - return not_preferred - - # No base was available with enough room. Find whichever base has the most room - # available so we lose as little as possible. The overfull list is already - # sorted by distance, and filtered for appropriate destinations. - base_for_fewest_losses: Optional[ControlPoint] = None - loss_count = math.inf - for airbase in overfull: - overflow = -( - airbase.unclaimed_parking() - - squadron.owned_aircraft - - squadron.pending_deliveries - ) - if overflow < loss_count: - loss_count = overflow - base_for_fewest_losses = airbase - return base_for_fewest_losses - - def _retreat_squadron(self, game: Game, squadron: Squadron) -> None: - destination = self.aircraft_retreat_destination(squadron) - if destination is None: - squadron.refund_orders() - self.capture_aircraft(game, squadron.aircraft, squadron.owned_aircraft) - return - logging.debug(f"{squadron} retreating to {destination} from {self}") - squadron.relocate_to(destination) - squadron.cancel_overflow_orders() - overflow = -destination.unclaimed_parking() - if overflow > 0: - logging.debug( - f"Not enough room for {squadron} at {destination}. Capturing " - f"{overflow} aircraft." - ) - self.capture_aircraft(game, squadron.aircraft, overflow) - squadron.owned_aircraft -= overflow - - def retreat_air_units(self, game: Game) -> None: - # TODO: Capture in order of price to retain maximum value? - for squadron in self.squadrons: - self._retreat_squadron(game, squadron) - - def depopulate_uncapturable_tgos(self) -> None: - # TODO Rework this. - for tgo in self.connected_objectives: - if not tgo.capturable: - tgo.clear() - - # TODO: Should be Airbase specific. - def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None: - new_coalition = game.coalition_for(for_player) - self.ground_unit_orders.refund_all(self.coalition) - self.retreat_ground_units(game) - self.retreat_air_units(game) - self.depopulate_uncapturable_tgos() - self._coalition = new_coalition - self.base.set_strength_to_minimum() - self._clear_front_lines(events) - self._create_missing_front_lines(game.laser_code_registry, events) - events.update_control_point(self) - - # All the attached TGOs have either been depopulated or captured. Tell the UI to - # update their state. Also update the orientation of all TGOs - iads_update_required = False - iads_network = game.theater.iads_network - for tgo in self.connected_objectives: - if isinstance(tgo, IadsGroundObject) or isinstance( - tgo, VehicleGroupGroundObject - ): - if not iads_update_required and tgo in iads_network.participating: - iads_update_required = True - conflict_heading = game.theater.heading_to_conflict_from(tgo.position) - tgo.rotate(conflict_heading or tgo.heading) - if not tgo.is_control_point: - events.update_tgo(tgo) - - # Update the IADS Network - if iads_update_required: - iads_network.update_network(events) - - @property - def required_aircraft_start_type(self) -> Optional[StartType]: - return None - - @abstractmethod - def can_operate(self, aircraft: AircraftType) -> bool: - ... - - def unclaimed_parking(self) -> int: - return self.total_aircraft_parking - self.allocated_aircraft().total - - @abstractmethod - def active_runway( - self, - theater: ConflictTheater, - conditions: Conditions, - dynamic_runways: Dict[str, RunwayData], - ) -> RunwayData: - ... - - def stub_runway_data(self) -> RunwayData: - return RunwayData( - self.full_name, runway_heading=Heading.from_degrees(0), runway_name="" - ) - - @property - def airdrome_id_for_landing(self) -> Optional[int]: - return None - - @property - def parking_slots(self) -> Iterator[ParkingSlot]: - yield from [] - - @property - @abstractmethod - def runway_is_destroyable(self) -> bool: - ... - - @property - @abstractmethod - def runway_status(self) -> RunwayStatus: - ... - - @abstractmethod - def describe_runway_status(self) -> str | None: - """Description of the runway status suitable for UI use.""" - - @property - def runway_can_be_repaired(self) -> bool: - return self.runway_status.needs_repair - - def begin_runway_repair(self) -> None: - if not self.runway_can_be_repaired: - logging.error(f"Cannot repair runway at {self}") - return - self.runway_status.begin_repair() - - def process_turn(self, game: Game) -> None: - # We're running at the end of the turn, so the time right now is irrelevant, and - # we don't know what time the next turn will start yet. It doesn't actually - # matter though, because the first thing the start of turn action will do is - # clear the ATO and replan the airlifts with the correct time. - self.ground_unit_orders.process(game, game.conditions.start_time) - - runway_status = self.runway_status - if runway_status is not None: - runway_status.process_turn() - - # Process movements for ships control points group - if self.target_position is not None: - delta = self.target_position - self.position - self.position = self.target_position - self.target_position = None - - # Move the linked unit groups - for ground_object in self.ground_objects: - if isinstance(ground_object, GenericCarrierGroundObject): - ground_object.position.x = ground_object.position.x + delta.x - ground_object.position.y = ground_object.position.y + delta.y - for group in ground_object.groups: - for u in group.units: - u.position.x = u.position.x + delta.x - u.position.y = u.position.y + delta.y - - def allocated_aircraft(self) -> AircraftAllocations: - present: dict[AircraftType, int] = defaultdict(int) - on_order: dict[AircraftType, int] = defaultdict(int) - transferring: dict[AircraftType, int] = defaultdict(int) - for squadron in self.squadrons: - present[squadron.aircraft] += squadron.owned_aircraft - if squadron.destination is None: - on_order[squadron.aircraft] += squadron.pending_deliveries - else: - transferring[squadron.aircraft] -= squadron.owned_aircraft - for squadron in self.coalition.air_wing.iter_squadrons(): - if squadron.destination == self: - on_order[squadron.aircraft] += squadron.pending_deliveries - transferring[squadron.aircraft] += squadron.owned_aircraft - - return AircraftAllocations(present, on_order, transferring) - - def allocated_ground_units( - self, transfers: PendingTransfers - ) -> GroundUnitAllocations: - on_order = {} - for unit_bought, count in self.ground_unit_orders.units.items(): - if isinstance(unit_bought, GroundUnitType): - on_order[unit_bought] = count - - transferring: dict[GroundUnitType, int] = defaultdict(int) - for transfer in transfers: - if transfer.destination == self: - for unit_type, count in transfer.units.items(): - transferring[unit_type] += count - - return GroundUnitAllocations( - self.base.armor, - on_order, - transferring, - ) - - @property - def income_per_turn(self) -> int: - return 0 - - @property - def has_active_frontline(self) -> bool: - return any(not c.is_friendly(self.captured) for c in self.connected_points) - - def front_is_active(self, other: ControlPoint) -> bool: - if other not in self.connected_points: - raise ValueError - - return self.captured != other.captured - - @property - def deployable_front_line_units(self) -> int: - return self.deployable_front_line_units_with(self.active_ammo_depots_count) - - def deployable_front_line_units_with(self, ammo_depot_count: int) -> int: - return min( - self.front_line_capacity_with(ammo_depot_count), self.base.total_armor - ) - - @classmethod - def front_line_capacity_with(cls, ammo_depot_count: int) -> int: - return ( - FREE_FRONTLINE_UNIT_SUPPLY - + ammo_depot_count * AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION - ) - - @property - def frontline_unit_count_limit(self) -> int: - return self.front_line_capacity_with(self.active_ammo_depots_count) - - @property - def all_ammo_depots(self) -> Iterator[TheaterGroundObject]: - for tgo in self.connected_objectives: - if tgo.is_ammo_depot: - yield tgo - - def ammo_depot_count(self, alive_only: bool = False) -> int: - return sum( - ammo_depot.alive_unit_count if alive_only else ammo_depot.unit_count - for ammo_depot in self.all_ammo_depots - ) - - @property - def active_ammo_depots_count(self) -> int: - """Return the number of available ammo depots""" - return self.ammo_depot_count(True) - - @property - def total_ammo_depots_count(self) -> int: - """Return the number of ammo depots, including dead ones""" - return self.ammo_depot_count() - - @property - def active_fuel_depots_count(self) -> int: - """Return the number of available fuel depots""" - return len( - [ - obj - for obj in self.connected_objectives - if obj.category == "fuel" and not obj.is_dead - ] - ) - - @property - def total_fuel_depots_count(self) -> int: - """Return the number of fuel depots, including dead ones""" - return len([obj for obj in self.connected_objectives if obj.category == "fuel"]) - - @property - def strike_targets(self) -> list[TheaterUnit]: - return [] - - @property - @abstractmethod - def category(self) -> str: - ... - - @property - @abstractmethod - def status(self) -> ControlPointStatus: - ... - - -class Airfield(ControlPoint): - def __init__( - self, airport: Airport, theater: ConflictTheater, starts_blue: bool - ) -> None: - super().__init__( - airport.name, - airport.position, - airport, - theater, - starts_blue, - cptype=ControlPointType.AIRBASE, - ) - self.airport = airport - self._runway_status = RunwayStatus() - - @property - def dcs_airport(self) -> Airport: - return self.airport - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_INSTALLATIONS, LandInstallationEntity.AIPORT_AIR_BASE - - def can_operate(self, aircraft: AircraftType) -> bool: - # TODO: Allow helicopters. - # Need to implement ground spawns so the helos don't use the runway. - # TODO: Allow harrier. - # Needs ground spawns just like helos do, but also need to be able to - # limit takeoff weight to ~20500 lbs or it won't be able to take off. - - # return false if aircraft is fixed wing and airport has no runways - if not aircraft.helicopter and not self.airport.runways: - return False - else: - return self.runway_is_operational() - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield from [ - FlightType.OCA_AIRCRAFT, - FlightType.OCA_RUNWAY, - FlightType.AIR_ASSAULT, - ] - - yield from super().mission_types(for_player) - - if self.is_friendly(for_player): - yield from [ - FlightType.AEWC, - # TODO: FlightType.INTERCEPTION - # TODO: FlightType.LOGISTICS - ] - - yield FlightType.REFUELING - - @property - def total_aircraft_parking(self) -> int: - """ - Return total aircraft parking slots available - Note : additional helipads shouldn't contribute to this score as it could allow airfield - to buy more planes than what they are able to host - """ - return len(self.airport.parking_slots) - - @property - def heading(self) -> Heading: - return Heading.from_degrees(self.airport.runways[0].heading) - - @property - def runway_is_destroyable(self) -> bool: - return True - - def runway_is_operational(self) -> bool: - return not self.runway_status.damaged - - @property - def runway_status(self) -> RunwayStatus: - return self._runway_status - - def describe_runway_status(self) -> str: - return f"Runway {self.runway_status.describe()}" - - def damage_runway(self) -> None: - self.runway_status.damage() - - def active_runway( - self, - theater: ConflictTheater, - conditions: Conditions, - dynamic_runways: Dict[str, RunwayData], - ) -> RunwayData: - if not self.airport.runways: - # Some airfields are heliports and don't have any runways. This isn't really - # the best fix, since we should still try to generate partial data for TACAN - # beacons, but it'll do for a bug fix, and the proper fix probably involves - # making heliports their own CP type. - # https://github.com/dcs-liberation/dcs_liberation/issues/2710 - return self.stub_runway_data() - - assigner = RunwayAssigner(conditions) - return assigner.get_preferred_runway(theater, self.airport) - - @property - def airdrome_id_for_landing(self) -> Optional[int]: - return self.airport.id - - @property - def parking_slots(self) -> Iterator[ParkingSlot]: - yield from self.airport.parking_slots - - @property - def can_deploy_ground_units(self) -> bool: - return True - - @property - def income_per_turn(self) -> int: - return 20 - - @property - def category(self) -> str: - return "airfield" - - @property - def status(self) -> ControlPointStatus: - runway_staus = self.runway_status - if runway_staus.needs_repair: - return ControlPointStatus.Destroyed - elif runway_staus.damaged: - return ControlPointStatus.Damaged - return ControlPointStatus.Functional - - -class NavalControlPoint(ControlPoint, ABC): - @property - def is_fleet(self) -> bool: - return True - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if self.is_friendly(for_player): - yield from [ - FlightType.AEWC, - FlightType.REFUELING, - # TODO: FlightType.INTERCEPTION - # TODO: Buddy tanking for the A-4? - # TODO: Rescue chopper? - # TODO: Inter-ship logistics? - ] - else: - yield FlightType.ANTISHIP - yield from super().mission_types(for_player) - - @property - def heading(self) -> Heading: - return Heading.from_degrees(0) # TODO compute heading - - def find_main_tgo(self) -> GenericCarrierGroundObject: - for g in self.ground_objects: - if isinstance(g, GenericCarrierGroundObject): - return g - raise RuntimeError(f"Found no carrier/LHA group for {self.name}") - - @property - def runway_is_destroyable(self) -> bool: - return False - - def runway_is_operational(self) -> bool: - # Necessary because it's possible for the carrier itself to have sunk - # while its escorts are still alive. - for group in self.find_main_tgo().groups: - for u in group.units: - if u.alive and u.type in [ - Ara_vdm, - Forrestal, - Hms_invincible, - KUZNECOW, - LHA_Tarawa, - Stennis, - Type_071, - ]: - return True - return False - - def active_runway( - self, - theater: ConflictTheater, - conditions: Conditions, - dynamic_runways: Dict[str, RunwayData], - ) -> RunwayData: - # TODO: Assign TACAN and ICLS earlier so we don't need this. - fallback = RunwayData( - self.full_name, runway_heading=Heading.from_degrees(0), runway_name="" - ) - return dynamic_runways.get(self.name, fallback) - - @property - def runway_status(self) -> RunwayStatus: - return RunwayStatus(damaged=not self.runway_is_operational()) - - def describe_runway_status(self) -> str: - return f"Flight deck {self.runway_status.describe()}" - - @property - def runway_can_be_repaired(self) -> bool: - return False - - @property - def max_move_distance(self) -> Distance: - return nautical_miles(80) - - @property - def can_deploy_ground_units(self) -> bool: - return False - - @property - def status(self) -> ControlPointStatus: - if not self.runway_is_operational(): - return ControlPointStatus.Destroyed - if self.find_main_tgo().dead_units: - return ControlPointStatus.Damaged - return ControlPointStatus.Functional - - -class Carrier(NavalControlPoint): - def __init__( - self, name: str, at: Point, theater: ConflictTheater, starts_blue: bool - ): - super().__init__( - name, - at, - at, - theater, - starts_blue, - cptype=ControlPointType.AIRCRAFT_CARRIER_GROUP, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.CARRIER - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - yield from super().mission_types(for_player) - if self.is_friendly(for_player): - yield from [ - # Nothing yet. - ] - - def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None: - raise RuntimeError("Carriers cannot be captured") - - @property - def is_carrier(self) -> bool: - return True - - def can_operate(self, aircraft: AircraftType) -> bool: - return aircraft.carrier_capable - - @property - def total_aircraft_parking(self) -> int: - return 90 - - @property - def category(self) -> str: - return "cv" - - -class Lha(NavalControlPoint): - def __init__( - self, name: str, at: Point, theater: ConflictTheater, starts_blue: bool - ): - super().__init__( - name, at, at, theater, starts_blue, cptype=ControlPointType.LHA_GROUP - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.AMPHIBIOUS_ASSAULT_SHIP_GENERAL - - def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None: - raise RuntimeError("LHAs cannot be captured") - - @property - def is_lha(self) -> bool: - return True - - def can_operate(self, aircraft: AircraftType) -> bool: - return aircraft.lha_capable - - @property - def total_aircraft_parking(self) -> int: - return 20 - - @property - def category(self) -> str: - return "lha" - - -class OffMapSpawn(ControlPoint): - def runway_is_operational(self) -> bool: - return True - - def __init__( - self, name: str, position: Point, theater: ConflictTheater, starts_blue: bool - ): - super().__init__( - name, - position, - position, - theater, - starts_blue, - cptype=ControlPointType.OFF_MAP, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_INSTALLATIONS, LandInstallationEntity.AIPORT_AIR_BASE - - def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None: - raise RuntimeError("Off map control points cannot be captured") - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - yield from [] - - @property - def total_aircraft_parking(self) -> int: - return 1000 - - def can_operate(self, aircraft: AircraftType) -> bool: - return True - - @property - def required_aircraft_start_type(self) -> Optional[StartType]: - return StartType.IN_FLIGHT - - @property - def heading(self) -> Heading: - return Heading.from_degrees(0) - - def active_runway( - self, - theater: ConflictTheater, - conditions: Conditions, - dynamic_runways: Dict[str, RunwayData], - ) -> RunwayData: - logging.warning("TODO: Off map spawns have no runways.") - return self.stub_runway_data() - - @property - def runway_is_destroyable(self) -> bool: - return False - - @property - def runway_status(self) -> RunwayStatus: - return RunwayStatus() - - def describe_runway_status(self) -> str: - return f"Off-map airport {self.runway_status.describe()}" - - @property - def can_deploy_ground_units(self) -> bool: - return False - - @property - def category(self) -> str: - return "offmap" - - @property - def status(self) -> ControlPointStatus: - return ControlPointStatus.Functional - - -class Fob(ControlPoint): - def __init__( - self, name: str, at: Point, theater: ConflictTheater, starts_blue: bool - ): - super().__init__( - name, at, at, theater, starts_blue, cptype=ControlPointType.FOB - ) - self.name = name - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_INSTALLATIONS, LandInstallationEntity.MILITARY_BASE - - @property - def runway_is_destroyable(self) -> bool: - return False - - def runway_is_operational(self) -> bool: - return self.has_helipads - - def active_runway( - self, - theater: ConflictTheater, - conditions: Conditions, - dynamic_runways: Dict[str, RunwayData], - ) -> RunwayData: - logging.warning("TODO: FOBs have no runways.") - return self.stub_runway_data() - - @property - def runway_status(self) -> RunwayStatus: - return RunwayStatus() - - def describe_runway_status(self) -> str | None: - if not self.has_helipads: - return None - return f"FARP {self.runway_status.describe()}" - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.STRIKE - yield FlightType.AIR_ASSAULT - else: - yield FlightType.AEWC - - yield from super().mission_types(for_player) - - @property - def total_aircraft_parking(self) -> int: - return len(self.helipads) - - def can_operate(self, aircraft: AircraftType) -> bool: - # FOBs and FARPs are the same class, distinguished only by non-FARP FOBs having - # zero parking. - # https://github.com/dcs-liberation/dcs_liberation/issues/2378 - return aircraft.helicopter and self.total_aircraft_parking > 0 - - @property - def heading(self) -> Heading: - return Heading.from_degrees(0) - - @property - def can_deploy_ground_units(self) -> bool: - return True - - @property - def income_per_turn(self) -> int: - return 10 - - @property - def category(self) -> str: - return "fob" - - @property - def status(self) -> ControlPointStatus: - return ControlPointStatus.Functional diff --git a/game/theater/daytimemap.py b/game/theater/daytimemap.py deleted file mode 100644 index 183483b5d..000000000 --- a/game/theater/daytimemap.py +++ /dev/null @@ -1,87 +0,0 @@ -from dataclasses import dataclass -from datetime import time -from typing import TypeAlias - -from game.timeofday import TimeOfDay - -TimeRange: TypeAlias = tuple[time, time] - - -@dataclass(frozen=True) -class DaytimeMap: - dawn: TimeRange - day: TimeRange - dusk: TimeRange - night: TimeRange - - def __post_init__(self) -> None: - # Checks that we only are even given whole-hour intervals. There's no reason to - # not support this eventually, but for now the fact that missions always start - # on the hour is a nice gameplay property. That'll have to go as a part of the - # mid-mission starts and removal of turns, but for now we can keep it to - # preserve the old behavior. - # - # Mission start time generation (currently in Conditions.generate_start_time) - # will need to be updated if and when this changes. - def check_time_is_hours(descr: str, t: time) -> None: - if t.minute: - raise ValueError( - f"{descr} has non-zero minutes; only hour intervals are currently " - "supported" - ) - if t.second: - raise ValueError( - f"{descr} has non-zero seconds; only hour intervals are currently " - "supported" - ) - if t.microsecond: - raise ValueError( - f"{descr} has non-zero microseconds; only hour intervals are " - "currently supported" - ) - - check_time_is_hours("dawn start", self.dawn[0]) - check_time_is_hours("dawn end", self.dawn[1]) - check_time_is_hours("day start", self.day[0]) - check_time_is_hours("day end", self.day[1]) - check_time_is_hours("dusk start", self.dusk[0]) - check_time_is_hours("dusk end", self.dusk[1]) - check_time_is_hours("night start", self.night[0]) - check_time_is_hours("night end", self.night[1]) - - def range_of(self, item: TimeOfDay) -> TimeRange: - match item: - case TimeOfDay.Dawn: - return self.dawn - case TimeOfDay.Day: - return self.day - case TimeOfDay.Dusk: - return self.dusk - case TimeOfDay.Night: - return self.night - case _: - raise ValueError(f"Invalid value for TimeOfDay: {item}") - - def best_guess_time_of_day_at(self, at: time) -> TimeOfDay: - """Returns an approximation of the time of day at the given time. - - This is the best guess because time ranges need not cover the whole day. For the - Caucasus, for example, dusk ends at 20:00 but night does not begin until 24:00. - If a time between those hours is given, we call it dusk. - """ - if self.night[0] < self.dawn[0] and at < self.night[0]: - # Night happens at or before midnight, so there's a time before dawn but - # after midnight where it can still be dusk. - return TimeOfDay.Dusk - if at < self.dawn[0]: - return TimeOfDay.Night - if at < self.day[0]: - return TimeOfDay.Dawn - if at < self.dusk[0]: - return TimeOfDay.Day - if self.night[0] > self.dusk[0] and at >= self.night[0]: - # Night happens before midnight, so it might still be dusk or night. - return TimeOfDay.Night - # If night starts at or before midnight, and it's at least dusk, it's definitely - # dusk. - return TimeOfDay.Dusk diff --git a/game/theater/frontline.py b/game/theater/frontline.py deleted file mode 100644 index 702e383f9..000000000 --- a/game/theater/frontline.py +++ /dev/null @@ -1,211 +0,0 @@ -from __future__ import annotations - -import logging -import uuid -from dataclasses import dataclass -from typing import Any, Iterator, List, TYPE_CHECKING, Tuple - -from dcs.mapping import Point - -from .missiontarget import MissionTarget -from ..lasercodes.lasercode import LaserCode -from ..utils import Heading, pairwise - -if TYPE_CHECKING: - from game.ato import FlightType - from .controlpoint import ControlPoint - - -FRONTLINE_MIN_CP_DISTANCE = 5000 - - -@dataclass -class FrontLineSegment: - """ - Describes a line segment of a FrontLine - """ - - point_a: Point - point_b: Point - - @property - def blue_forward_heading(self) -> Heading: - """The heading toward the start of the next red segment or red base.""" - return Heading.from_degrees(self.point_a.heading_between_point(self.point_b)) - - @property - def length(self) -> float: - """Length of the segment""" - return self.point_a.distance_to_point(self.point_b) - - -class FrontLine(MissionTarget): - """Defines a front line location between two control points. - Front lines are the area where ground combat happens. - Overwrites the entirety of MissionTarget __init__ method to allow for - dynamic position calculation. - """ - - def __init__( - self, - blue_point: ControlPoint, - red_point: ControlPoint, - laser_code: LaserCode, - ) -> None: - self.id = uuid.uuid4() - self.blue_cp = blue_point - self.red_cp = red_point - self.laser_code = laser_code - try: - route = list(blue_point.convoy_route_to(red_point)) - except KeyError: - # Some campaigns are air only and the mission generator currently relies on - # *some* "front line" being drawn between these two. In this case there will - # be no supply route to follow. Just create an arbitrary route between the - # two points. - route = [blue_point.position, red_point.position] - # Snap the beginning and end points to the CPs rather than the convoy waypoints, - # which are on roads. - route[0] = blue_point.position - route[-1] = red_point.position - self.segments: List[FrontLineSegment] = [ - FrontLineSegment(a, b) for a, b in pairwise(route) - ] - super().__init__( - f"Front line {blue_point}/{red_point}", self._compute_position() - ) - - def __eq__(self, other: Any) -> bool: - if not isinstance(other, FrontLine): - return False - return (self.blue_cp, self.red_cp) == (other.blue_cp, other.red_cp) - - def __hash__(self) -> int: - return hash(id(self)) - - def _compute_position(self) -> Point: - return self.point_along_route_from_blue(self._blue_route_progress) - - def update_position(self) -> None: - self.position = self._compute_position() - - def control_point_friendly_to(self, player: bool) -> ControlPoint: - if player: - return self.blue_cp - return self.red_cp - - def control_point_hostile_to(self, player: bool) -> ControlPoint: - return self.control_point_friendly_to(not player) - - def is_friendly(self, to_player: bool) -> bool: - """Returns True if the objective is in friendly territory.""" - return False - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - yield from [ - FlightType.CAS, - FlightType.AEWC, - FlightType.REFUELING - # TODO: FlightType.TROOP_TRANSPORT - # TODO: FlightType.EVAC - ] - yield from super().mission_types(for_player) - - @property - def points(self) -> Iterator[Point]: - yield self.segments[0].point_a - for segment in self.segments: - yield segment.point_b - - @property - def control_points(self) -> Tuple[ControlPoint, ControlPoint]: - """Returns a tuple of the two control points.""" - return self.blue_cp, self.red_cp - - @property - def route_length(self) -> float: - """The total distance of all segments""" - return sum(i.length for i in self.segments) - - @property - def blue_forward_heading(self) -> Heading: - """The heading toward the start of the next red segment or red base.""" - return self.active_segment.blue_forward_heading - - @property - def active_segment(self) -> FrontLineSegment: - """The FrontLine segment where there can be an active conflict""" - if self._blue_route_progress <= self.segments[0].length: - return self.segments[0] - - distance_to_segment = self._blue_route_progress - for segment in self.segments: - if distance_to_segment <= segment.length: - return segment - else: - distance_to_segment -= segment.length - logging.error( - "Frontline attack distance is greater than the sum of its segments" - ) - return self.segments[0] - - def point_along_route_from_blue(self, distance: float) -> Point: - """Returns a point {distance} away from control_point_a along the route.""" - if distance < self.segments[0].length: - return self.blue_cp.position.point_from_heading( - self.segments[0].blue_forward_heading.degrees, distance - ) - remaining_dist = distance - for segment in self.segments: - if remaining_dist < segment.length: - return segment.point_a.point_from_heading( - segment.blue_forward_heading.degrees, remaining_dist - ) - else: - remaining_dist -= segment.length - raise RuntimeError( - f"Could not find front line point {distance} from {self.blue_cp}" - ) - - @property - def _blue_route_progress(self) -> float: - """ - The distance from point "a" where the conflict should occur - according to the current strength of each control point - """ - total_strength = self.blue_cp.base.strength + self.red_cp.base.strength - if self.blue_cp.base.strength == 0: - return self._adjust_for_min_dist(0) - if self.red_cp.base.strength == 0: - return self._adjust_for_min_dist(self.route_length) - strength_pct = self.blue_cp.base.strength / total_strength - return self._adjust_for_min_dist(strength_pct * self.route_length) - - def _adjust_for_min_dist(self, distance: float) -> float: - """ - Ensures the frontline conflict is never located within the minimum distance - constant of either end control point. - """ - if (distance > self.route_length / 2) and ( - distance + FRONTLINE_MIN_CP_DISTANCE > self.route_length - ): - distance = self.route_length - FRONTLINE_MIN_CP_DISTANCE - elif (distance < self.route_length / 2) and ( - distance < FRONTLINE_MIN_CP_DISTANCE - ): - distance = FRONTLINE_MIN_CP_DISTANCE - return distance - - @staticmethod - def sort_control_points( - a: ControlPoint, b: ControlPoint - ) -> tuple[ControlPoint, ControlPoint]: - if a.is_friendly_to(b): - raise ValueError( - "Cannot sort control points that are friendly to each other" - ) - if a.captured: - return a, b - return b, a diff --git a/game/theater/iadsnetwork/iadsnetwork.py b/game/theater/iadsnetwork/iadsnetwork.py deleted file mode 100644 index 28bbc204e..000000000 --- a/game/theater/iadsnetwork/iadsnetwork.py +++ /dev/null @@ -1,322 +0,0 @@ -from __future__ import annotations -from collections import defaultdict -from dataclasses import dataclass, field - -import logging -from typing import TYPE_CHECKING, Iterator, Optional -from uuid import UUID -import uuid -from game.theater.iadsnetwork.iadsrole import IadsRole -from game.dcs.groundunittype import GroundUnitType -from game.theater.theatergroundobject import ( - IadsBuildingGroundObject, - IadsGroundObject, - NavalGroundObject, - TheaterGroundObject, -) -from game.theater.theatergroup import IadsGroundGroup - -if TYPE_CHECKING: - from game.game import Game - from game.sim import GameUpdateEvents - - -class IadsNetworkException(Exception): - pass - - -@dataclass -class SkynetNode: - """Dataclass for a SkynetNode used in the LUA Data table by the luagenerator""" - - dcs_name: str - player: bool - iads_role: IadsRole - properties: dict[str, str] = field(default_factory=dict) - connections: dict[str, list[str]] = field(default_factory=lambda: defaultdict(list)) - - @staticmethod - def dcs_name_for_group(group: IadsGroundGroup) -> str: - if group.iads_role in [ - IadsRole.EWR, - IadsRole.COMMAND_CENTER, - IadsRole.CONNECTION_NODE, - IadsRole.POWER_SOURCE, - ]: - # Use UnitName for EWR, CommandCenter, Comms, Power - is_dead = group.alive_units == 0 - for unit in group.units: - if unit.alive or (is_dead and unit.is_static): - # Return first alive unit within the group or otherwise return the - # first static object as these will still be added to the mission - return unit.unit_name - # Raise error if there is no skynet capable unit in this group - raise IadsNetworkException(f"Group {group.name} has no skynet usable units") - else: - # Use the GroupName for SAMs, SAMAsEWR and PDs - return group.group_name - - @classmethod - def from_group(cls, group: IadsGroundGroup) -> SkynetNode: - node = cls( - cls.dcs_name_for_group(group), - group.ground_object.is_friendly(True), - group.iads_role, - ) - unit_type = group.units[0].unit_type - if unit_type is not None and isinstance(unit_type, GroundUnitType): - node.properties = unit_type.skynet_properties.to_dict() - return node - - -class IadsNetworkNode: - """IadsNetworkNode which particicpates to the IADS Network and has connections to Power Sources, Comms or Point Defenses. A network node can be a SAM System, EWR or Command Center""" - - def __init__(self, group: IadsGroundGroup) -> None: - self.group = group - self.connections: dict[UUID, IadsGroundGroup] = {} - - def __str__(self) -> str: - return self.group.group_name - - def add_secondary_node(self, tgo: TheaterGroundObject) -> None: - """Add all possible connections for the given secondary node to this node""" - for group in tgo.groups: - if isinstance(group, IadsGroundGroup) and group.iads_role.is_secondary_node: - self.add_connection_for_group(group) - - def add_connection_for_group(self, group: IadsGroundGroup) -> None: - """Add connection for the given GroundGroup with unique ID""" - self.connections[uuid.uuid4()] = group - - -class IadsNetwork: - """IADS Network consisting of multiple Network nodes and connections. The Network represents all possible connections of ground objects regardless if a tgo is under control of red or blue. The network can run in either advanced or basic mode. The advanced network can be created by a given configuration in the campaign yaml or computed by Range. The basic mode is a fallback mode which does not use Comms, Power or Command Centers. The network will be used to visualize all connections at the map and for creating the needed Lua data for the skynet plugin""" - - def __init__( - self, advanced: bool, iads_data: list[str | dict[str, list[str]]] - ) -> None: - self.advanced_iads = advanced - self.ground_objects: dict[str, TheaterGroundObject] = {} - self.nodes: list[IadsNetworkNode] = [] - self.iads_config: dict[str, list[str]] = defaultdict(list) - - # Load Iads config from the campaign data - for element in iads_data: - if isinstance(element, str): - self.iads_config[element] = [] - elif isinstance(element, dict): - for iads_node, iads_connections in element.items(): - self.iads_config[iads_node] = iads_connections - else: - raise RuntimeError("Invalid iads_config in campaign") - - @property - def participating(self) -> Iterator[TheaterGroundObject]: - """All unique participating TGOs. First primary then secondary""" - secondary_nodes = [] - for node in self.nodes: - yield node.group.ground_object - for connection in node.connections.values(): - # Check for duplicate secondary node as a secondary node can be - # connected to 1..N primary nodes but we do not want to yiel them - # multiple times so we prevent dups - if connection.ground_object not in secondary_nodes: - secondary_nodes.append(connection.ground_object) - yield from secondary_nodes - - def skynet_nodes(self, game: Game) -> list[SkynetNode]: - """Get all skynet nodes from the IADS Network""" - skynet_nodes: list[SkynetNode] = [] - for node in self.nodes: - if game.iads_considerate_culling(node.group.ground_object): - # Skip culled ground objects - continue - - if node.group.alive_units == 0 and not node.group.has_statics: - # Skip non-static nodes with no alive units left - # Dead static nodes can be added to skynet as these are added to the - # mission as dead unit. Non static will not be added to the mission and - # are therefore not accessible by skynet - continue - - # SkynetNode.from_group(node.group) may raise an exception - # (originating from SkynetNode.dcs_name_for_group) - # but if it does, we want to know because it's supposed to be impossible afaict - skynet_node = SkynetNode.from_group(node.group) - for connection in node.connections.values(): - if connection.alive_units == 0 and not connection.has_statics: - # Skip non static and dead connection nodes. See comment above - continue - if connection.ground_object.is_friendly( - skynet_node.player - ) and not game.iads_considerate_culling(connection.ground_object): - skynet_node.connections[connection.iads_role.value].append( - SkynetNode.dcs_name_for_group(connection) - ) - skynet_nodes.append(skynet_node) - return skynet_nodes - - def update_tgo(self, tgo: TheaterGroundObject, events: GameUpdateEvents) -> None: - """Update the IADS Network for the given TGO""" - # Remove existing nodes for the given tgo if there are any - for cn in self.nodes: - if cn.group.ground_object == tgo: - self.nodes.remove(cn) - # Also delete all connections for the given node - for cID in cn.connections: - events.delete_iads_connection(cID) - - # Try to create a new primary node for the TGO - node = self._new_node_for_tgo(tgo) - if node is None: - # the ground object is not participating to the IADS Network - return - - if self.advanced_iads: - # Create the connections to the secondary nodes - if self.iads_config: - # If iads_config was defined and campaign designer added a config for - # the given primary node generate the connections from the config. If - # the primary node was not defined in the iads_config it will be added - # without any connections - self._add_connections_from_config(node) - else: - # Otherwise calculate the connections by range - self._calculate_connections_by_range(node) - - events.update_iads_node(node) - - def update_network(self, events: GameUpdateEvents) -> None: - """Update all primary nodes of the IADS and recalculate connections""" - primary_nodes = [node.group.ground_object for node in self.nodes] - for primary_node in primary_nodes: - self.update_tgo(primary_node, events) - - def node_for_tgo(self, tgo: TheaterGroundObject) -> Optional[IadsNetworkNode]: - """Create Primary node for the TGO or return existing one""" - for cn in self.nodes: - if cn.group.ground_object == tgo: - return cn - return self._new_node_for_tgo(tgo) - - def _new_node_for_tgo(self, tgo: TheaterGroundObject) -> Optional[IadsNetworkNode]: - """Create a new primary node for the given TGO. - - Will return None if the given TGO is not capable of being a primary node. - This will also add any PointDefense of this TGO to the primary node""" - node: Optional[IadsNetworkNode] = None - for group in tgo.groups: - if isinstance(group, IadsGroundGroup): - # The first IadsGroundGroup is always the primary Group - if node is None and group.iads_role.is_primary_node: - # Create Primary Node - node = IadsNetworkNode(group) - self.nodes.append(node) - elif node is not None and group.iads_role == IadsRole.POINT_DEFENSE: - # Point Defense Node for this TGO - node.add_connection_for_group(group) - - if node is None: - logging.debug(f"TGO {tgo.name} not participating to IADS") - return node - - def initialize_network(self, ground_objects: Iterator[TheaterGroundObject]) -> None: - """Initialize the IADS network in advanced or basic mode depending on the campaign""" - for tgo in ground_objects: - self.ground_objects[tgo.original_name] = tgo - if self.advanced_iads: - # Advanced mode - if self.iads_config: - # Load from Configuration File - self.initialize_network_from_config() - else: - # Load from Range - self.initialize_network_from_range() - - # basic mode if no advanced iads support or network init created no connections - if not self.nodes: - self.initialize_basic_iads() - - def initialize_basic_iads(self) -> None: - """Initialize the IADS Network in basic mode (SAM & EWR only)""" - for go in self.ground_objects.values(): - if isinstance(go, IadsGroundObject): - self.node_for_tgo(go) - - def initialize_network_from_config(self) -> None: - """Initialize the IADS Network from a configuration""" - for primary_node in self.iads_config.keys(): - warning_msg = ( - f"IADS: No ground object found for {primary_node}." - f" This can be normal behaviour." - ) - if primary_node in self.ground_objects: - node = self.node_for_tgo(self.ground_objects[primary_node]) - else: - node = None - warning_msg = ( - f"IADS: No ground object found for connection {primary_node}" - ) - - if node is None: - # Log a warning as this can be normal. Possible case is for example - # when the campaign request a Long Range SAM but the faction has none - # available. Therefore the TGO will not get populated at all - logging.warning(warning_msg) - continue - self._add_connections_from_config(node) - - def _add_connections_from_config(self, node: IadsNetworkNode) -> None: - """Add all connections for the given primary node based on the iads_config""" - primary_node = node.group.ground_object.original_name - # iads_config uses defaultdict, therefore when the connections of a primary - # node where not defined in the iads_config they will just be empty - connections = self.iads_config[primary_node] - for secondary_node in connections: - try: - nearby_go = self.ground_objects[secondary_node] - if IadsRole.for_category(nearby_go.category).is_secondary_node: - node.add_secondary_node(nearby_go) - else: - logging.error( - f"IADS: {secondary_node} is not a valid secondary node" - ) - except KeyError: - logging.exception( - f"IADS: No ground object found for connection {secondary_node}" - ) - continue - - def _calculate_connections_by_range(self, node: IadsNetworkNode) -> None: - """Add all connections for the primary node by calculating them by range""" - primary_tgo = node.group.ground_object - for nearby_go in self.ground_objects.values(): - # Find nearby Power or Connection - if nearby_go == primary_tgo: - continue - nearby_iads_role = IadsRole.for_category(nearby_go.category) - if ( - nearby_iads_role.is_secondary_node - and nearby_go.position.distance_to_point(primary_tgo.position) - <= nearby_iads_role.connection_range.meters - ): - node.add_secondary_node(nearby_go) - - def initialize_network_from_range(self) -> None: - """Initialize the IADS Network by range""" - for go in self.ground_objects.values(): - if ( - isinstance(go, IadsGroundObject) - or isinstance(go, NavalGroundObject) - or ( - isinstance(go, IadsBuildingGroundObject) - and IadsRole.for_category(go.category) == IadsRole.COMMAND_CENTER - ) - ): - # Set as primary node - node = self.node_for_tgo(go) - if node is None: - # TGO does not participate to iads network - continue - self._calculate_connections_by_range(node) diff --git a/game/theater/iadsnetwork/iadsrole.py b/game/theater/iadsnetwork/iadsrole.py deleted file mode 100644 index 5dd0fe14e..000000000 --- a/game/theater/iadsnetwork/iadsrole.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass, field -from enum import Enum -from game.data.groups import GroupTask - -from game.utils import Distance - - -class IadsRole(Enum): - #: A radar SAM that should be controlled by Skynet. - SAM = "Sam" - - #: A radar SAM that should be controlled and used as an EWR by Skynet. - SAM_AS_EWR = "SamAsEwr" - - #: An air defense unit that should be used as point defense by Skynet. - POINT_DEFENSE = "PD" - - #: An ewr unit that should provide information to the Skynet IADS. - EWR = "Ewr" - - #: IADS Elements which allow the advanced functions of Skynet. - CONNECTION_NODE = "ConnectionNode" - POWER_SOURCE = "PowerSource" - COMMAND_CENTER = "CommandCenter" - - #: All other types of groups that might be present in a SAM TGO. This includes - #: SHORADS, AAA, supply trucks, etc. Anything that shouldn't be controlled by Skynet - #: should use this role. - NO_BEHAVIOR = "NoBehavior" - - @classmethod - def for_task(cls, task: GroupTask) -> IadsRole: - if task == GroupTask.COMMS: - return cls.CONNECTION_NODE - elif task == GroupTask.POWER: - return cls.POWER_SOURCE - elif task == GroupTask.COMMAND_CENTER: - return cls.COMMAND_CENTER - elif task == GroupTask.POINT_DEFENSE: - return cls.POINT_DEFENSE - elif task == GroupTask.LORAD: - return cls.SAM_AS_EWR - elif task == GroupTask.MERAD: - return cls.SAM - elif task in [ - GroupTask.EARLY_WARNING_RADAR, - GroupTask.NAVY, - GroupTask.AIRCRAFT_CARRIER, - GroupTask.HELICOPTER_CARRIER, - ]: - return cls.EWR - return cls.NO_BEHAVIOR - - @classmethod - def for_category(cls, category: str) -> IadsRole: - if category == "comms": - return cls.CONNECTION_NODE - elif category == "power": - return cls.POWER_SOURCE - elif category == "commandcenter": - return cls.COMMAND_CENTER - return cls.NO_BEHAVIOR - - @property - def connection_range(self) -> Distance: - if self == IadsRole.CONNECTION_NODE: - return Distance(27780) # 15nm - elif self == IadsRole.POWER_SOURCE: - return Distance(64820) # 35nm - return Distance(0) - - @property - def participate(self) -> bool: - # Returns true if the Role participates in the skynet - # This will exclude NoBehaviour and PD for the time beeing - return self not in [ - IadsRole.NO_BEHAVIOR, - IadsRole.POINT_DEFENSE, - ] - - @property - def is_primary_node(self) -> bool: - return self in [ - IadsRole.SAM, - IadsRole.SAM_AS_EWR, - IadsRole.EWR, - IadsRole.COMMAND_CENTER, - ] - - @property - def is_secondary_node(self) -> bool: - return self in [IadsRole.CONNECTION_NODE, IadsRole.POWER_SOURCE] diff --git a/game/theater/landmap.py b/game/theater/landmap.py deleted file mode 100644 index 6e59237b8..000000000 --- a/game/theater/landmap.py +++ /dev/null @@ -1,139 +0,0 @@ -from dataclasses import dataclass -import pickle -from functools import cached_property -from typing import Optional, Tuple, Union -import logging -from pathlib import Path -from typing import List - -from shapely import geometry -from shapely.geometry import MultiPolygon, Polygon - -from dcs.drawing.drawing import LineStyle, Rgba -from dcs.drawing.polygon import FreeFormPolygon -from dcs.mapping import Point -from dcs.mission import Mission -from dcs.terrain.terrain import Terrain - - -@dataclass(frozen=True) -class Landmap: - inclusion_zones: MultiPolygon - exclusion_zones: MultiPolygon - sea_zones: MultiPolygon - - def __post_init__(self) -> None: - if not self.inclusion_zones.is_valid: - raise RuntimeError("Inclusion zones not valid") - if not self.exclusion_zones.is_valid: - raise RuntimeError("Exclusion zones not valid") - if not self.sea_zones.is_valid: - raise RuntimeError("Sea zones not valid") - - @cached_property - def inclusion_zone_only(self) -> MultiPolygon: - return self.inclusion_zones - self.exclusion_zones - self.sea_zones - - -def load_landmap(filename: Path) -> Optional[Landmap]: - try: - with open(filename, "rb") as f: - return pickle.load(f) - except: - logging.exception(f"Failed to load landmap {filename}") - return None - - -def poly_contains(x: float, y: float, poly: Union[MultiPolygon, Polygon]) -> bool: - return poly.contains(geometry.Point(x, y)) - - -def to_miz(landmap: Landmap, terrain: Terrain, mission_filename: str) -> None: - """ - Writes landmap to .miz file so that zones can be visualized and edited in the - mission editor. - """ - - def multi_polygon_to_miz( - mission: Mission, - terrain: Terrain, - multi_polygon: MultiPolygon, - color: Rgba, - prefix: str, - layer_index: int = 4, - layer_name: str = "Author", - ) -> None: - reference_position = Point(0, 0, terrain) - for i in range(len(multi_polygon.geoms)): - polygon = multi_polygon.geoms[i] - if len(polygon.interiors) > 0: - raise ValueError( - f"Polygon hole found when trying to export {prefix} {i}. to_miz() does not support landmap zones with holes." - ) - coordinates = polygon.exterior.xy - points = [] - for j in range(len(coordinates[0])): - points.append(Point(coordinates[0][j], coordinates[1][j], terrain)) - polygon_drawing = FreeFormPolygon( - visible=True, - position=reference_position, - name=f"{prefix}-{i}", - color=color, - layer_name=layer_name, - fill=color, - line_thickness=10, - line_style=LineStyle.Solid, - points=points, - ) - mission.drawings.layers[layer_index].objects.append(polygon_drawing) - - mission = Mission(terrain=terrain) - multi_polygon_to_miz( - mission, terrain, landmap.exclusion_zones, Rgba(255, 0, 0, 128), "Exclusion" - ) - multi_polygon_to_miz( - mission, terrain, landmap.sea_zones, Rgba(0, 0, 255, 128), "Sea" - ) - multi_polygon_to_miz( - mission, terrain, landmap.inclusion_zones, Rgba(0, 255, 0, 128), "Inclusion" - ) - mission.save(mission_filename) - - -def from_miz(mission_filename: str, layer_index: int = 4) -> Landmap: - """ - Generate Landmap object from Free Form Polygons drawn in a .miz file. - Landmap.inclusion_zones are expected to be named Inclusion- - Landmap.exclusion_zones are expected to be named Exclusion- - Landmap.sea_zones are expected to be named Sea- - """ - mission = Mission() - mission.load_file(mission_filename) - polygons: dict[str, List[Polygon]] = {"Inclusion": [], "Exclusion": [], "Sea": []} - for draw_object in mission.drawings.layers[layer_index].objects: - if type(draw_object) != FreeFormPolygon: - logging.debug( - f"Object {draw_object.name} is not a FreeFormPolygon, ignoring" - ) - continue - name_split = draw_object.name.split( - "-" - ) # names are in the format - - zone_type = name_split[0] - if len(name_split) != 2 or zone_type not in ("Exclusion", "Sea", "Inclusion"): - logging.debug( - f"Object name {draw_object.name} does not conform to expected format -, ignoring" - ) - continue - polygon_points = [] - for point in draw_object.points: - polygon_points.append( - (point.x + draw_object.position.x, point.y + draw_object.position.y) - ) - polygons[zone_type].append(Polygon(polygon_points)) - landmap = Landmap( - inclusion_zones=MultiPolygon(polygons["Inclusion"]), - exclusion_zones=MultiPolygon(polygons["Exclusion"]), - sea_zones=MultiPolygon(polygons["Sea"]), - ) - return landmap diff --git a/game/theater/missiontarget.py b/game/theater/missiontarget.py deleted file mode 100644 index eeeb5dc70..000000000 --- a/game/theater/missiontarget.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -from collections.abc import Sequence -from typing import Iterator, TYPE_CHECKING, Union - -from dcs.mapping import Point -from dcs.unit import Unit - -if TYPE_CHECKING: - from game.ato.flighttype import FlightType - from game.theater import TheaterUnit - - -class MissionTarget: - def __init__(self, name: str, position: Point) -> None: - """Initializes a mission target. - - Args: - name: The name of the mission target. - position: The location of the mission target. - """ - self.name = name - self.position = position - - def distance_to(self, other: MissionTarget) -> float: - """Computes the distance to the given mission target.""" - return self.position.distance_to_point(other.position) - - def is_friendly(self, to_player: bool) -> bool: - """Returns True if the objective is in friendly territory.""" - raise NotImplementedError - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if self.is_friendly(for_player): - yield FlightType.BARCAP - else: - yield from [ - FlightType.ESCORT, - FlightType.TARCAP, - FlightType.SEAD_ESCORT, - FlightType.SWEEP, - # TODO: FlightType.ELINT, - # TODO: FlightType.EWAR, - # TODO: FlightType.RECON, - ] - - @property - def strike_targets(self) -> list[TheaterUnit]: - return [] diff --git a/game/theater/presetlocation.py b/game/theater/presetlocation.py deleted file mode 100644 index fcb9b7e82..000000000 --- a/game/theater/presetlocation.py +++ /dev/null @@ -1,34 +0,0 @@ -from __future__ import annotations - -from typing import TypeVar - -from dcs.mapping import Point -from dcs.unitgroup import StaticGroup, ShipGroup, VehicleGroup - -from game.point_with_heading import PointWithHeading -from game.utils import Heading - -GroupT = TypeVar("GroupT", StaticGroup, ShipGroup, VehicleGroup) - - -class PresetLocation(PointWithHeading): - """Store information about the Preset Location set by the campaign designer""" - - # This allows to store original name and force a specific type or template - original_name: str # Store the original name from the campaign miz - - def __init__( - self, name: str, position: Point, heading: Heading = Heading.from_degrees(0) - ) -> None: - super().__init__(position.x, position.y, heading, position._terrain) - self.original_name = name - - @classmethod - def from_group(cls, group: GroupT) -> PresetLocation: - """Creates a PresetLocation from a placeholder group in the campaign miz""" - preset = PresetLocation( - group.name, - group.position, - Heading.from_degrees(group.units[0].heading), - ) - return preset diff --git a/game/theater/seasonalconditions.py b/game/theater/seasonalconditions.py deleted file mode 100644 index fa91764f0..000000000 --- a/game/theater/seasonalconditions.py +++ /dev/null @@ -1,53 +0,0 @@ -import datetime -from dataclasses import dataclass -from enum import Enum - - -class Season(Enum): - Winter = "winter" - Spring = "spring" - Summer = "summer" - Fall = "fall" - - -def determine_season(day: datetime.date) -> Season: - # Note: This logic doesn't need to be very precise - # Currently refers strictly to northern-hemisphere seasons - day_of_year = day.timetuple().tm_yday - season_length = 365.0 / 4 - winter_end_day = season_length / 2 - if day_of_year < winter_end_day: - return Season.Winter - elif day_of_year < winter_end_day + season_length: - return Season.Spring - elif day_of_year < winter_end_day + season_length * 2: - return Season.Summer - elif day_of_year < winter_end_day + season_length * 3: - return Season.Fall - else: - return Season.Winter - - -@dataclass(frozen=True) -class WeatherTypeChances: - thunderstorm: float - raining: float - cloudy: float - clear_skies: float - - -@dataclass(frozen=True) -class SeasonalConditions: - # Units are inHg and degrees Celsius - summer_avg_pressure: float - winter_avg_pressure: float - summer_avg_temperature: float - winter_avg_temperature: float - temperature_day_night_difference: float - - high_avg_yearly_turbulence_per_10cm: float - low_avg_yearly_turbulence_per_10cm: float - solar_noon_turbulence_per_10cm: float - midnight_turbulence_per_10cm: float - - weather_type_chances: dict[Season, WeatherTypeChances] diff --git a/game/theater/start_generator.py b/game/theater/start_generator.py deleted file mode 100644 index ef043717d..000000000 --- a/game/theater/start_generator.py +++ /dev/null @@ -1,533 +0,0 @@ -from __future__ import annotations - -import logging -import random -from dataclasses import dataclass, fields -from datetime import datetime, time -from pathlib import Path -from typing import List - -import dcs.statics -import yaml - -from game import Game -from game.factions.faction import Faction -from game.naming import namegen -from game.scenery_group import SceneryGroup -from game.theater import PointWithHeading, PresetLocation -from game.theater.theatergroundobject import ( - BuildingGroundObject, - IadsBuildingGroundObject, -) -from game.utils import Heading, escape_string_for_lua -from game.version import VERSION -from . import ( - ConflictTheater, - ControlPoint, - ControlPointType, - Fob, - OffMapSpawn, -) -from .theatergroup import IadsGroundGroup, IadsRole, SceneryUnit, TheaterGroup -from ..armedforces.armedforces import ArmedForces -from ..armedforces.forcegroup import ForceGroup -from ..campaignloader.campaignairwingconfig import CampaignAirWingConfig -from ..data.groups import GroupTask -from ..persistence.paths import liberation_user_dir -from ..plugins import LuaPluginManager -from ..profiling import logged_duration -from ..settings import Settings - - -@dataclass(frozen=True) -class GeneratorSettings: - start_date: datetime - start_time: time | None - player_budget: int - enemy_budget: int - inverted: bool - advanced_iads: bool - no_carrier: bool - no_lha: bool - no_player_navy: bool - no_enemy_navy: bool - - -@dataclass -class ModSettings: - a4_skyhawk: bool = False - f22_raptor: bool = False - f104_starfighter: bool = False - f4_phantom: bool = False - hercules: bool = False - uh_60l: bool = False - jas39_gripen: bool = False - su57_felon: bool = False - frenchpack: bool = False - high_digit_sams: bool = False - ov10a_bronco: bool = False - fa18efg: bool = False - - def save_player_settings(self) -> None: - """Saves the player's global settings to the user directory.""" - settings: dict[str, dict[str, bool]] = {} - for field in fields(self): - settings[field.name] = self.__dict__[field.name] - - with self._player_settings_file.open("w", encoding="utf-8") as settings_file: - yaml.dump(settings, settings_file, sort_keys=False, explicit_start=True) - - def merge_player_settings(self) -> None: - """Updates with the player's global settings.""" - settings_path = self._player_settings_file - if not settings_path.exists(): - return - with settings_path.open(encoding="utf-8") as settings_file: - data = yaml.safe_load(settings_file) - - for mod_name, enabled in data.items(): - if mod_name not in self.__dict__: - logging.warning( - "Unexpected mod key found in %s: %s. Ignoring.", - settings_path, - mod_name, - ) - continue - self.__dict__[mod_name] = enabled - - @property - def _player_settings_file(self) -> Path: - """Returns the path to the player's global settings file.""" - return liberation_user_dir() / "mods.yaml" - - -class GameGenerator: - def __init__( - self, - player: Faction, - enemy: Faction, - theater: ConflictTheater, - air_wing_config: CampaignAirWingConfig, - settings: Settings, - generator_settings: GeneratorSettings, - mod_settings: ModSettings, - lua_plugin_manager: LuaPluginManager, - ) -> None: - self.player = player - self.enemy = enemy - self.theater = theater - self.air_wing_config = air_wing_config - self.settings = settings - self.generator_settings = generator_settings - self.player.apply_mod_settings(mod_settings) - self.enemy.apply_mod_settings(mod_settings) - self.lua_plugin_manager = lua_plugin_manager - - def generate(self) -> Game: - with logged_duration("TGO population"): - # Reset name generator - namegen.reset() - self.prepare_theater() - game = Game( - player_faction=self.player, - enemy_faction=self.enemy, - theater=self.theater, - air_wing_config=self.air_wing_config, - start_date=self.generator_settings.start_date, - start_time=self.generator_settings.start_time, - settings=self.settings, - lua_plugin_manager=self.lua_plugin_manager, - player_budget=self.generator_settings.player_budget, - enemy_budget=self.generator_settings.enemy_budget, - ) - - GroundObjectGenerator(game, self.generator_settings).generate() - game.settings.version = VERSION - return game - - def should_remove_carrier(self, player: bool) -> bool: - faction = self.player if player else self.enemy - return self.generator_settings.no_carrier or not faction.carrier_names - - def should_remove_lha(self, player: bool) -> bool: - faction = self.player if player else self.enemy - return self.generator_settings.no_lha or not faction.helicopter_carrier_names - - def prepare_theater(self) -> None: - to_remove: List[ControlPoint] = [] - - # Remove carrier and lha, invert situation if needed - for cp in self.theater.controlpoints: - if self.generator_settings.inverted: - cp.starts_blue = cp.captured_invert - - if cp.is_carrier and self.should_remove_carrier(cp.starts_blue): - to_remove.append(cp) - elif cp.is_lha and self.should_remove_lha(cp.starts_blue): - to_remove.append(cp) - - # do remove - for cp in to_remove: - self.theater.controlpoints.remove(cp) - - -class ControlPointGroundObjectGenerator: - def __init__( - self, - game: Game, - generator_settings: GeneratorSettings, - control_point: ControlPoint, - ) -> None: - self.game = game - self.generator_settings = generator_settings - self.control_point = control_point - - @property - def faction_name(self) -> str: - return self.faction.name - - @property - def faction(self) -> Faction: - return self.game.coalition_for(self.control_point.captured).faction - - @property - def armed_forces(self) -> ArmedForces: - return self.game.coalition_for(self.control_point.captured).armed_forces - - def generate(self) -> bool: - self.control_point.connected_objectives = [] - self.generate_navy() - return True - - def generate_ground_object_from_group( - self, unit_group: ForceGroup, location: PresetLocation - ) -> None: - ground_object = unit_group.generate( - namegen.random_objective_name(), - location, - self.control_point, - self.game, - ) - self.control_point.connected_objectives.append(ground_object) - - def generate_navy(self) -> None: - skip_player_navy = self.generator_settings.no_player_navy - if self.control_point.captured and skip_player_navy: - return - skip_enemy_navy = self.generator_settings.no_enemy_navy - if not self.control_point.captured and skip_enemy_navy: - return - for position in self.control_point.preset_locations.ships: - unit_group = self.armed_forces.random_group_for_task(GroupTask.NAVY) - if not unit_group: - logging.warning(f"{self.faction_name} has no ForceGroup for Navy") - return - self.generate_ground_object_from_group(unit_group, position) - - -class NoOpGroundObjectGenerator(ControlPointGroundObjectGenerator): - def generate(self) -> bool: - return True - - -class GenericCarrierGroundObjectGenerator(ControlPointGroundObjectGenerator): - def update_carrier_name(self, carrier_name: str) -> None: - # Set Control Point name - self.control_point.name = carrier_name - - # Set UnitName. First unit of the TGO is always the carrier - carrier = next(self.control_point.ground_objects[-1].units) - carrier.name = carrier_name - - -class CarrierGroundObjectGenerator(GenericCarrierGroundObjectGenerator): - def generate(self) -> bool: - if not super().generate(): - return False - - carrier_names = self.faction.carrier_names - if not carrier_names: - logging.info( - f"Skipping generation of {self.control_point.name} because " - f"{self.faction_name} has no carriers" - ) - return False - - unit_group = self.armed_forces.random_group_for_task(GroupTask.AIRCRAFT_CARRIER) - if not unit_group: - logging.error(f"{self.faction_name} has no access to AircraftCarrier") - return False - self.generate_ground_object_from_group( - unit_group, - PresetLocation( - self.control_point.name, - self.control_point.position, - self.control_point.heading, - ), - ) - self.update_carrier_name(random.choice(carrier_names)) - return True - - -class LhaGroundObjectGenerator(GenericCarrierGroundObjectGenerator): - def generate(self) -> bool: - if not super().generate(): - return False - - lha_names = self.faction.helicopter_carrier_names - if not lha_names: - logging.info( - f"Skipping generation of {self.control_point.name} because " - f"{self.faction_name} has no LHAs" - ) - return False - - unit_group = self.armed_forces.random_group_for_task( - GroupTask.HELICOPTER_CARRIER - ) - if not unit_group: - logging.error(f"{self.faction_name} has no access to HelicopterCarrier") - return False - self.generate_ground_object_from_group( - unit_group, - PresetLocation( - self.control_point.name, - self.control_point.position, - self.control_point.heading, - ), - ) - self.update_carrier_name(random.choice(lha_names)) - return True - - -class AirbaseGroundObjectGenerator(ControlPointGroundObjectGenerator): - def __init__( - self, - game: Game, - generator_settings: GeneratorSettings, - control_point: ControlPoint, - ) -> None: - super().__init__(game, generator_settings, control_point) - - def generate(self) -> bool: - if not super().generate(): - return False - - self.generate_ground_points() - return True - - def generate_ground_points(self) -> None: - """Generate ground objects and AA sites for the control point.""" - self.generate_armor_groups() - self.generate_iads() - self.generate_scenery_sites() - self.generate_strike_targets() - self.generate_offshore_strike_targets() - self.generate_factories() - self.generate_ammunition_depots() - self.generate_missile_sites() - self.generate_coastal_sites() - - def generate_armor_groups(self) -> None: - for position in self.control_point.preset_locations.armor_groups: - unit_group = self.armed_forces.random_group_for_task(GroupTask.BASE_DEFENSE) - if not unit_group: - logging.error(f"{self.faction_name} has no ForceGroup for Armor") - return - self.generate_ground_object_from_group(unit_group, position) - - def generate_aa(self) -> None: - presets = self.control_point.preset_locations - aa_tasking = [GroupTask.AAA] - for position in presets.aaa: - self.generate_aa_at(position, aa_tasking) - aa_tasking.insert(0, GroupTask.SHORAD) - for position in presets.short_range_sams: - self.generate_aa_at(position, aa_tasking) - aa_tasking.insert(0, GroupTask.MERAD) - for position in presets.medium_range_sams: - self.generate_aa_at(position, aa_tasking) - aa_tasking.insert(0, GroupTask.LORAD) - for position in presets.long_range_sams: - self.generate_aa_at(position, aa_tasking) - - def generate_ewrs(self) -> None: - for position in self.control_point.preset_locations.ewrs: - unit_group = self.armed_forces.random_group_for_task( - GroupTask.EARLY_WARNING_RADAR - ) - if not unit_group: - logging.error(f"{self.faction_name} has no ForceGroup for EWR") - return - self.generate_ground_object_from_group(unit_group, position) - - def generate_building_at( - self, - group_task: GroupTask, - location: PresetLocation, - ) -> None: - # GroupTask is the type of the building to be generated - unit_group = self.armed_forces.random_group_for_task(group_task) - if not unit_group: - raise RuntimeError( - f"{self.faction_name} has no access to Building {group_task.description}" - ) - self.generate_ground_object_from_group(unit_group, location) - - def generate_ammunition_depots(self) -> None: - for position in self.control_point.preset_locations.ammunition_depots: - self.generate_building_at(GroupTask.AMMO, position) - - def generate_factories(self) -> None: - for position in self.control_point.preset_locations.factories: - self.generate_building_at(GroupTask.FACTORY, position) - - def generate_aa_at(self, location: PresetLocation, tasks: list[GroupTask]) -> None: - for task in tasks: - unit_group = self.armed_forces.random_group_for_task(task) - if unit_group: - # Only take next (smaller) aa_range when no template available for the - # most requested range. Otherwise break the loop and continue - self.generate_ground_object_from_group(unit_group, location) - return - - logging.error( - f"{self.faction_name} has no access to SAM {', '.join([task.description for task in tasks])}" - ) - - def generate_iads(self) -> None: - # AntiAir - self.generate_aa() - # EWR - self.generate_ewrs() - # IADS Buildings - for iads_element in self.control_point.preset_locations.iads_command_center: - self.generate_building_at(GroupTask.COMMAND_CENTER, iads_element) - for iads_element in self.control_point.preset_locations.iads_connection_node: - self.generate_building_at(GroupTask.COMMS, iads_element) - for iads_element in self.control_point.preset_locations.iads_power_source: - self.generate_building_at(GroupTask.POWER, iads_element) - - def generate_scenery_sites(self) -> None: - presets = self.control_point.preset_locations - for scenery_group in presets.scenery: - self.generate_tgo_for_scenery(scenery_group) - - def generate_tgo_for_scenery(self, scenery: SceneryGroup) -> None: - # Special Handling for scenery Objects based on trigger zones - iads_role = IadsRole.for_category(scenery.category) - tgo_type = ( - IadsBuildingGroundObject if iads_role.participate else BuildingGroundObject - ) - g = tgo_type( - namegen.random_objective_name(), - scenery.category, - PresetLocation(scenery.name, scenery.centroid), - self.control_point, - ) - ground_group = TheaterGroup( - self.game.next_group_id(), - scenery.name, - PointWithHeading.from_point(scenery.centroid, Heading.from_degrees(0)), - [], - g, - ) - if iads_role.participate: - ground_group = IadsGroundGroup.from_group(ground_group) - ground_group.iads_role = iads_role - - g.groups.append(ground_group) - # Each nested trigger zone is a target/building/unit for an objective. - for zone in scenery.target_zones: - zone.name = escape_string_for_lua(zone.name) - scenery_unit = SceneryUnit( - zone.id, - zone.name, - dcs.statics.Fortification.White_Flag, - PointWithHeading.from_point(zone.position, Heading.from_degrees(0)), - g, - ) - scenery_unit.zone = zone - ground_group.units.append(scenery_unit) - - self.control_point.connected_objectives.append(g) - - def generate_missile_sites(self) -> None: - for position in self.control_point.preset_locations.missile_sites: - unit_group = self.armed_forces.random_group_for_task(GroupTask.MISSILE) - if not unit_group: - logging.warning(f"{self.faction_name} has no ForceGroup for Missile") - return - self.generate_ground_object_from_group(unit_group, position) - - def generate_coastal_sites(self) -> None: - for position in self.control_point.preset_locations.coastal_defenses: - unit_group = self.armed_forces.random_group_for_task(GroupTask.COASTAL) - if not unit_group: - logging.warning(f"{self.faction_name} has no ForceGroup for Coastal") - return - self.generate_ground_object_from_group(unit_group, position) - - def generate_strike_targets(self) -> None: - for position in self.control_point.preset_locations.strike_locations: - self.generate_building_at(GroupTask.STRIKE_TARGET, position) - - def generate_offshore_strike_targets(self) -> None: - for position in self.control_point.preset_locations.offshore_strike_locations: - self.generate_building_at(GroupTask.OIL, position) - - -class FobGroundObjectGenerator(AirbaseGroundObjectGenerator): - def generate(self) -> bool: - if super(FobGroundObjectGenerator, self).generate(): - self.generate_fob() - return True - return False - - def generate_fob(self) -> None: - self.generate_building_at( - GroupTask.FOB, - PresetLocation( - self.control_point.name, - self.control_point.position, - self.control_point.heading, - ), - ) - - -class GroundObjectGenerator: - def __init__(self, game: Game, generator_settings: GeneratorSettings) -> None: - self.game = game - self.generator_settings = generator_settings - - def generate(self) -> None: - # Copied so we can remove items from the original list without breaking - # the iterator. - control_points = list(self.game.theater.controlpoints) - for control_point in control_points: - if not self.generate_for_control_point(control_point): - self.game.theater.controlpoints.remove(control_point) - - def generate_for_control_point(self, control_point: ControlPoint) -> bool: - generator: ControlPointGroundObjectGenerator - if control_point.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP: - generator = CarrierGroundObjectGenerator( - self.game, self.generator_settings, control_point - ) - elif control_point.cptype == ControlPointType.LHA_GROUP: - generator = LhaGroundObjectGenerator( - self.game, self.generator_settings, control_point - ) - elif isinstance(control_point, OffMapSpawn): - generator = NoOpGroundObjectGenerator( - self.game, self.generator_settings, control_point - ) - elif isinstance(control_point, Fob): - generator = FobGroundObjectGenerator( - self.game, self.generator_settings, control_point - ) - else: - generator = AirbaseGroundObjectGenerator( - self.game, self.generator_settings, control_point - ) - return generator.generate() diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py deleted file mode 100644 index 28834a9d6..000000000 --- a/game/theater/theatergroundobject.py +++ /dev/null @@ -1,663 +0,0 @@ -from __future__ import annotations - -import itertools -import uuid -from abc import ABC -from typing import Any, Iterator, List, Optional, TYPE_CHECKING - -from dcs.mapping import Point - -from shapely.geometry import Point as ShapelyPoint - -from game.sidc import ( - Entity, - LandEquipmentEntity, - LandInstallationEntity, - LandUnitEntity, - SeaSurfaceEntity, - SidcDescribable, - StandardIdentity, - Status, - SymbolSet, -) -from game.theater.presetlocation import PresetLocation -from .missiontarget import MissionTarget -from ..utils import Distance, Heading, meters - -if TYPE_CHECKING: - from game.ato.flighttype import FlightType - from game.threatzones import ThreatPoly - from .theatergroup import TheaterUnit, TheaterGroup - from .controlpoint import ControlPoint - - -NAME_BY_CATEGORY = { - "ewr": "Early Warning Radar", - "aa": "AA Defense Site", - "allycamp": "Camp", - "ammo": "Ammo depot", - "armor": "Armor group", - "coastal": "Coastal defense", - "commandcenter": "Command Center", - "comms": "Communications tower", - "derrick": "Derrick", - "factory": "Factory", - "farp": "FARP", - "fob": "FOB", - "fuel": "Fuel depot", - "missile": "Missile site", - "oil": "Oil platform", - "power": "Power plant", - "ship": "Ship", - "village": "Village", - "ware": "Warehouse", - "ww2bunker": "Bunker", -} - - -class TheaterGroundObject(MissionTarget, SidcDescribable, ABC): - def __init__( - self, - name: str, - category: str, - location: PresetLocation, - control_point: ControlPoint, - sea_object: bool, - ) -> None: - super().__init__(name, location) - self.id = uuid.uuid4() - self.category = category - self.heading = location.heading - self.control_point = control_point - self.sea_object = sea_object - self.groups: List[TheaterGroup] = [] - self.original_name = location.original_name - self._threat_poly: ThreatPoly | None = None - - def __getstate__(self) -> dict[str, Any]: - state = self.__dict__.copy() - del state["_threat_poly"] - return state - - def __setstate__(self, state: dict[str, Any]) -> None: - state["_threat_poly"] = None - self.__dict__.update(state) - - @property - def sidc_status(self) -> Status: - if self.is_dead: - return Status.PRESENT_DESTROYED - elif self.dead_units: - return Status.PRESENT_DAMAGED - else: - return Status.PRESENT - - @property - def standard_identity(self) -> StandardIdentity: - return ( - StandardIdentity.FRIEND - if self.control_point.captured - else StandardIdentity.HOSTILE_FAKER - ) - - @property - def is_dead(self) -> bool: - return self.alive_unit_count == 0 - - @property - def units(self) -> Iterator[TheaterUnit]: - """ - :return: all the units at this location - """ - yield from itertools.chain.from_iterable([g.units for g in self.groups]) - - @property - def statics(self) -> Iterator[TheaterUnit]: - for group in self.groups: - for unit in group.units: - if unit.is_static: - yield unit - - @property - def dead_units(self) -> list[TheaterUnit]: - """ - :return: all the dead units at this location - """ - return [unit for unit in self.units if not unit.alive] - - @property - def group_name(self) -> str: - """The name of the unit group.""" - return f"{self.category}|{self.name}" - - @property - def display_name(self) -> str: - """The display name of the tgo which will be shown on the map.""" - return self.group_name - - @property - def waypoint_name(self) -> str: - return f"[{self.name}] {self.category}" - - def __str__(self) -> str: - return NAME_BY_CATEGORY[self.category] - - @property - def obj_name(self) -> str: - return self.name - - @property - def faction_color(self) -> str: - return "BLUE" if self.control_point.captured else "RED" - - def is_friendly(self, to_player: bool) -> bool: - return self.control_point.is_friendly(to_player) - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if self.is_friendly(for_player): - yield from [ - # TODO: FlightType.LOGISTICS - # TODO: FlightType.TROOP_TRANSPORT - ] - else: - yield from [ - FlightType.STRIKE, - FlightType.REFUELING, - ] - yield from super().mission_types(for_player) - - @property - def unit_count(self) -> int: - return sum(g.unit_count for g in self.groups) - - @property - def alive_unit_count(self) -> int: - return sum(g.alive_units for g in self.groups) - - @property - def has_aa(self) -> bool: - """Returns True if the ground object contains a working anti air unit""" - return any(u.alive and u.is_anti_air for u in self.units) - - @property - def has_live_radar_sam(self) -> bool: - """Returns True if the ground object contains a unit with working radar SAM.""" - return any(g.max_threat_range(radar_only=True) for g in self.groups) - - def max_detection_range(self) -> Distance: - """Calculate the maximum detection range of the ground object""" - return max((g.max_detection_range() for g in self.groups), default=meters(0)) - - def max_threat_range(self) -> Distance: - """Calculate the maximum threat range of the ground object""" - return max((g.max_threat_range() for g in self.groups), default=meters(0)) - - def threat_poly(self) -> ThreatPoly | None: - if self._threat_poly is None: - self._threat_poly = self._make_threat_poly() - return self._threat_poly - - def invalidate_threat_poly(self) -> None: - self._threat_poly = None - - def _make_threat_poly(self) -> ThreatPoly | None: - threat_range = self.max_threat_range() - if not threat_range: - return None - - point = ShapelyPoint(self.position.x, self.position.y) - return point.buffer(threat_range.meters) - - @property - def is_ammo_depot(self) -> bool: - return self.category == "ammo" - - @property - def is_factory(self) -> bool: - return self.category == "factory" - - @property - def is_control_point(self) -> bool: - """True if this TGO is the group for the control point itself (CVs and FOBs).""" - return False - - @property - def strike_targets(self) -> list[TheaterUnit]: - return [unit for unit in self.units if unit.alive] - - @property - def mark_locations(self) -> Iterator[Point]: - yield self.position - - def clear(self) -> None: - self.invalidate_threat_poly() - self.groups = [] - - @property - def capturable(self) -> bool: - raise NotImplementedError - - @property - def purchasable(self) -> bool: - raise NotImplementedError - - @property - def value(self) -> int: - """The value of all units of the Ground Objects""" - return sum(u.unit_type.price for u in self.units if u.unit_type and u.alive) - - def group_by_name(self, name: str) -> Optional[TheaterGroup]: - for group in self.groups: - if group.name == name: - return group - return None - - def rotate(self, heading: Heading) -> None: - """Rotate the whole TGO clockwise to the new heading""" - rotation = heading - self.heading - if rotation.degrees < 0: - rotation = Heading.from_degrees(rotation.degrees + 360) - - self.heading = heading - # Rotate the whole TGO to match the new heading - for unit in self.units: - unit.position.heading += rotation - unit.position.rotate(self.position, rotation) - - @property - def should_head_to_conflict(self) -> bool: - """Should this TGO head towards the closest conflict to work properly?""" - return False - - -class BuildingGroundObject(TheaterGroundObject): - def __init__( - self, - name: str, - category: str, - location: PresetLocation, - control_point: ControlPoint, - is_fob_structure: bool = False, - ) -> None: - super().__init__( - name=name, - category=category, - location=location, - control_point=control_point, - sea_object=False, - ) - self.is_fob_structure = is_fob_structure - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - if self.category == "allycamp": - entity = LandInstallationEntity.TENTED_CAMP - elif self.category == "ammo": - entity = LandInstallationEntity.AMMUNITION_CACHE - elif self.category == "commandcenter": - entity = LandInstallationEntity.MILITARY_INFRASTRUCTURE - elif self.category == "comms": - entity = LandInstallationEntity.TELECOMMUNICATIONS_TOWER - elif self.category == "derrick": - entity = LandInstallationEntity.PETROLEUM_FACILITY - elif self.category == "factory": - entity = LandInstallationEntity.MAINTENANCE_FACILITY - elif self.category == "farp": - entity = LandInstallationEntity.HELICOPTER_LANDING_SITE - elif self.category == "fuel": - entity = LandInstallationEntity.WAREHOUSE_STORAGE_FACILITY - elif self.category == "oil": - entity = LandInstallationEntity.PETROLEUM_FACILITY - elif self.category == "power": - entity = LandInstallationEntity.GENERATION_STATION - elif self.category == "village": - entity = LandInstallationEntity.PUBLIC_VENUES_INFRASTRUCTURE - elif self.category == "ware": - entity = LandInstallationEntity.WAREHOUSE_STORAGE_FACILITY - elif self.category == "ww2bunker": - entity = LandInstallationEntity.MILITARY_BASE - else: - raise ValueError(f"Unhandled building category: {self.category}") - return SymbolSet.LAND_INSTALLATIONS, entity - - @property - def mark_locations(self) -> Iterator[Point]: - # Special handling to mark all buildings of the TGO - for unit in self.strike_targets: - yield unit.position - - @property - def is_control_point(self) -> bool: - return self.is_fob_structure - - @property - def capturable(self) -> bool: - return True - - @property - def purchasable(self) -> bool: - return False - - -class NavalGroundObject(TheaterGroundObject, ABC): - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.ANTISHIP - yield from super().mission_types(for_player) - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return False - - -class GenericCarrierGroundObject(NavalGroundObject, ABC): - @property - def is_control_point(self) -> bool: - return True - - -# TODO: Why is this both a CP and a TGO? -class CarrierGroundObject(GenericCarrierGroundObject): - def __init__( - self, name: str, location: PresetLocation, control_point: ControlPoint - ) -> None: - super().__init__( - name=name, - category="CARRIER", - location=location, - control_point=control_point, - sea_object=True, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.CARRIER - - def __str__(self) -> str: - return f"CV {self.name}" - - -# TODO: Why is this both a CP and a TGO? -class LhaGroundObject(GenericCarrierGroundObject): - def __init__( - self, name: str, location: PresetLocation, control_point: ControlPoint - ) -> None: - super().__init__( - name=name, - category="LHA", - location=location, - control_point=control_point, - sea_object=True, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.AMPHIBIOUS_ASSAULT_SHIP_GENERAL - - def __str__(self) -> str: - return f"LHA {self.name}" - - -class MissileSiteGroundObject(TheaterGroundObject): - def __init__( - self, name: str, location: PresetLocation, control_point: ControlPoint - ) -> None: - super().__init__( - name=name, - category="missile", - location=location, - control_point=control_point, - sea_object=False, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_UNIT, LandUnitEntity.MISSILE - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return False - - @property - def should_head_to_conflict(self) -> bool: - return True - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.BAI - for mission_type in super().mission_types(for_player): - yield mission_type - - -class CoastalSiteGroundObject(TheaterGroundObject): - def __init__( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> None: - super().__init__( - name=name, - category="coastal", - location=location, - control_point=control_point, - sea_object=False, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_UNIT, LandUnitEntity.MISSILE - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return False - - @property - def should_head_to_conflict(self) -> bool: - return True - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.BAI - for mission_type in super().mission_types(for_player): - yield mission_type - - -class IadsGroundObject(TheaterGroundObject, ABC): - def __init__( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - category: str = "aa", - ) -> None: - super().__init__( - name=name, - category=category, - location=location, - control_point=control_point, - sea_object=False, - ) - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.DEAD - yield from super().mission_types(for_player) - - @property - def should_head_to_conflict(self) -> bool: - return True - - -# The SamGroundObject represents all type of AA -# The TGO can have multiple types of units (AAA,SAM,Support...) -# Differentiation can be made during generation with the airdefensegroupgenerator -class SamGroundObject(IadsGroundObject): - def __init__( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> None: - super().__init__( - name=name, - category="aa", - location=location, - control_point=control_point, - ) - - @property - def sidc_status(self) -> Status: - if self.is_dead: - return Status.PRESENT_DESTROYED - elif self.dead_units: - if self.max_threat_range() > meters(0): - return Status.PRESENT - else: - return Status.PRESENT_DAMAGED - else: - return Status.PRESENT_FULLY_CAPABLE - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_UNIT, LandUnitEntity.AIR_DEFENSE - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.DEAD - yield FlightType.SEAD - for mission_type in super().mission_types(for_player): - # We yielded this ourselves to move it to the top of the list. Don't yield - # it twice. - if mission_type is not FlightType.DEAD: - yield mission_type - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return True - - -class VehicleGroupGroundObject(TheaterGroundObject): - def __init__( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> None: - super().__init__( - name=name, - category="armor", - location=location, - control_point=control_point, - sea_object=False, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return ( - SymbolSet.LAND_UNIT, - LandUnitEntity.ARMOR_ARMORED_MECHANIZED_SELF_PROPELLED_TRACKED, - ) - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return True - - @property - def should_head_to_conflict(self) -> bool: - return True - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield FlightType.BAI - yield from super().mission_types(for_player) - - -class EwrGroundObject(IadsGroundObject): - def __init__( - self, - name: str, - location: PresetLocation, - control_point: ControlPoint, - ) -> None: - super().__init__( - name=name, - location=location, - control_point=control_point, - category="ewr", - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.LAND_EQUIPMENT, LandEquipmentEntity.RADAR - - @property - def capturable(self) -> bool: - return False - - @property - def purchasable(self) -> bool: - return True - - -class ShipGroundObject(NavalGroundObject): - def __init__( - self, name: str, location: PresetLocation, control_point: ControlPoint - ) -> None: - super().__init__( - name=name, - category="ship", - location=location, - control_point=control_point, - sea_object=True, - ) - - @property - def symbol_set_and_entity(self) -> tuple[SymbolSet, Entity]: - return SymbolSet.SEA_SURFACE, SeaSurfaceEntity.SURFACE_COMBATANT_LINE - - -class IadsBuildingGroundObject(BuildingGroundObject): - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - from game.ato import FlightType - - if not self.is_friendly(for_player): - yield from [FlightType.STRIKE, FlightType.DEAD] - skippers = [FlightType.STRIKE] # prevent yielding twice - for mission_type in super().mission_types(for_player): - if mission_type not in skippers: - yield mission_type diff --git a/game/theater/theatergroup.py b/game/theater/theatergroup.py deleted file mode 100644 index 2f7cc68d6..000000000 --- a/game/theater/theatergroup.py +++ /dev/null @@ -1,256 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Any, Optional, TYPE_CHECKING, Type - -from dcs.triggers import TriggerZone -from dcs.unittype import ShipType, StaticType, UnitType as DcsUnitType, VehicleType - -from game.data.radar_db import LAUNCHER_TRACKER_PAIRS, TELARS, TRACK_RADARS -from game.data.units import ANTI_AIR_UNIT_CLASSES -from game.dcs.groundunittype import GroundUnitType -from game.dcs.shipunittype import ShipUnitType -from game.dcs.unittype import UnitType -from game.point_with_heading import PointWithHeading -from game.theater.iadsnetwork.iadsrole import IadsRole -from game.utils import Heading, Distance, meters - -if TYPE_CHECKING: - from game.layout.layout import LayoutUnit - from game.sim import GameUpdateEvents - from game.theater.theatergroundobject import TheaterGroundObject - - -@dataclass -class TheaterUnit: - """Representation of a single Unit in the Game""" - - # Every Unit has a unique ID generated from the game - id: int - # The name of the Unit. Not required to be unique - name: str - # DCS UniType of the unit - type: Type[DcsUnitType] - # Position and orientation of the Unit - position: PointWithHeading - # The parent ground object - ground_object: TheaterGroundObject - # Number of hit points the unit has - hit_points: Optional[int] = None - # State of the unit, dead or alive - alive: bool = True - - @staticmethod - def from_template( - id: int, dcs_type: Type[DcsUnitType], t: LayoutUnit, go: TheaterGroundObject - ) -> TheaterUnit: - unit = TheaterUnit( - id, - t.name, - dcs_type, - PointWithHeading.from_point(t.position, Heading.from_degrees(t.heading)), - go, - ) - # if the TheaterUnit represents a GroundUnitType or ShipUnitType, initialize health to full hit points - if unit.unit_type is not None: - unit.hit_points = unit.unit_type.hit_points - return unit - - @property - def unit_type(self) -> Optional[UnitType[Any]]: - if issubclass(self.type, VehicleType): - return next(GroundUnitType.for_dcs_type(self.type)) - elif issubclass(self.type, ShipType): - return next(ShipUnitType.for_dcs_type(self.type)) - # None for not available StaticTypes - return None - - def kill(self, events: GameUpdateEvents) -> None: - self.alive = False - self.ground_object.invalidate_threat_poly() - events.update_tgo(self.ground_object) - - @property - def unit_name(self) -> str: - return f"{str(self.id).zfill(4)} | {self.name}" - - @property - def display_name(self) -> str: - unit_label = self.unit_type or self.type.name or self.name - return f"{str(self.id).zfill(4)} | {unit_label}{self._status_label()}" - - @property - def short_name(self) -> str: - return f"{self.type.id[0:18]} {self._status_label()}" - - @property - def is_static(self) -> bool: - return issubclass(self.type, StaticType) - - @property - def is_vehicle(self) -> bool: - return issubclass(self.type, VehicleType) - - @property - def is_ship(self) -> bool: - return issubclass(self.type, ShipType) - - @property - def is_anti_air(self) -> bool: - return ( - self.unit_type is not None - and self.unit_type.unit_class in ANTI_AIR_UNIT_CLASSES - ) - - @property - def icon(self) -> str: - return self.type.id - - @property - def repairable(self) -> bool: - # Only let units with UnitType be repairable as we just have prices for them - return self.unit_type is not None - - @property - def detection_range(self) -> Distance: - unit_range = getattr(self.type, "detection_range", None) - return meters(unit_range if unit_range is not None and self.alive else 0) - - @property - def threat_range(self) -> Distance: - unit_range = getattr(self.type, "threat_range", None) - return meters(unit_range if unit_range is not None and self.alive else 0) - - def _status_label(self) -> str: - if not self.alive: - return " [DEAD]" - if self.unit_type is None: - return "" - if self.hit_points is None: - return "" - if self.unit_type.hit_points == self.hit_points: - return "" - damage_percentage = 100 - int(100 * self.hit_points / self.unit_type.hit_points) - return f" [DAMAGED {damage_percentage}%]" - - -class SceneryUnit(TheaterUnit): - """Special TheaterUnit for handling scenery ground objects""" - - # Scenery Objects are identified by a special trigger zone - zone: TriggerZone - - @property - def display_name(self) -> str: - dead_label = " [DEAD]" if not self.alive else "" - return f"{str(self.id).zfill(4)} | {self.name}{dead_label}" - - @property - def short_name(self) -> str: - dead_label = " [DEAD]" if not self.alive else "" - return f"{self.name[0:18]} {dead_label}" - - @property - def icon(self) -> str: - return "missing" - - @property - def repairable(self) -> bool: - return False - - -@dataclass -class TheaterGroup: - """Logical group for multiple TheaterUnits at a specific position""" - - # Every Theater Group has a unique ID generated from the game - id: int # Unique ID - # The name of the Group. Not required to be unique - name: str - # Position and orientation of the Group - position: PointWithHeading - # All TheaterUnits within the group - units: list[TheaterUnit] - # The parent ground object - ground_object: TheaterGroundObject - - @staticmethod - def from_template( - id: int, - name: str, - units: list[TheaterUnit], - go: TheaterGroundObject, - ) -> TheaterGroup: - return TheaterGroup( - id, - name, - PointWithHeading.from_point(go.position, go.heading), - units, - go, - ) - - @property - def group_name(self) -> str: - return f"{str(self.id).zfill(4)} | {self.name}" - - @property - def unit_count(self) -> int: - return len(self.units) - - @property - def alive_units(self) -> int: - return sum(unit.alive for unit in self.units) - - @property - def has_statics(self) -> bool: - return any(unit.is_static for unit in self.units) - - def max_detection_range(self) -> Distance: - """Calculate the maximum detection range of the TheaterGroup""" - ranges = (u.detection_range for u in self.units if u.is_anti_air) - return max(ranges, default=meters(0)) - - def max_threat_range(self, radar_only: bool = False) -> Distance: - """Calculate the maximum threat range of the TheaterGroup. - This also checks for Launcher and Tracker Pairs and if they are functioning or not. Allows to also use only radar emitting units for the calculation with the parameter. - """ - max_non_radar = meters(0) - max_telar_range = meters(0) - max_tel_range = meters(0) - live_trs = set() - launchers: dict[Type[VehicleType], Distance] = {} - for unit in self.units: - if not unit.alive or not unit.is_anti_air: - continue - if unit.type in TRACK_RADARS: - live_trs.add(unit.type) - elif unit.type in TELARS: - max_telar_range = max(max_telar_range, unit.threat_range) - elif ( - issubclass(unit.type, VehicleType) - and unit.type in LAUNCHER_TRACKER_PAIRS - ): - launchers[unit.type] = unit.threat_range - else: - max_non_radar = max(max_non_radar, unit.threat_range) - for launcher, threat_range in launchers.items(): - if LAUNCHER_TRACKER_PAIRS[launcher] in live_trs: - max_tel_range = max(max_tel_range, threat_range) - if radar_only: - return max(max_tel_range, max_telar_range) - return max(max_tel_range, max_telar_range, max_non_radar) - - -class IadsGroundGroup(TheaterGroup): - # IADS GroundObject Groups have a specific Role for the system - iads_role: IadsRole = IadsRole.NO_BEHAVIOR - - @staticmethod - def from_group(group: TheaterGroup) -> IadsGroundGroup: - return IadsGroundGroup( - group.id, - group.name, - group.position, - group.units, - group.ground_object, - ) diff --git a/game/theater/theaterloader.py b/game/theater/theaterloader.py deleted file mode 100644 index 339ec9143..000000000 --- a/game/theater/theaterloader.py +++ /dev/null @@ -1,184 +0,0 @@ -from __future__ import annotations - -import datetime -from collections.abc import Iterator -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import yaml -from dcs.terrain import ( - Caucasus, - Falklands, - MarianaIslands, - Nevada, - Normandy, - PersianGulf, - Sinai, - Syria, - TheChannel, -) - -from .conflicttheater import ConflictTheater -from .daytimemap import DaytimeMap -from .landmap import load_landmap -from .seasonalconditions import Season, SeasonalConditions, WeatherTypeChances - -ALL_TERRAINS = [ - Caucasus(), - Falklands(), - PersianGulf(), - Normandy(), - MarianaIslands(), - Nevada(), - TheChannel(), - Sinai(), - Syria(), -] - -TERRAINS_BY_NAME = {t.name: t for t in ALL_TERRAINS} - - -@dataclass(frozen=True) -class SeasonData: - average_temperature: float | None - average_pressure: float | None - weather: WeatherTypeChances - - @staticmethod - def from_yaml(data: dict[str, Any]) -> SeasonData: - return SeasonData( - data.get("average_temperature"), - data.get("average_pressure"), - WeatherTypeChances( - data["weather"]["thunderstorm"], - data["weather"]["raining"], - data["weather"]["cloudy"], - data["weather"]["clear"], - ), - ) - - -@dataclass(frozen=True) -class TurbulenceData: - high_avg_yearly_turbulence_per_10cm: float | None - low_avg_yearly_turbulence_per_10cm: float | None - solar_noon_turbulence_per_10cm: float | None - midnight_turbulence_per_10cm: float | None - - @staticmethod - def from_yaml(data: dict[str, Any]) -> TurbulenceData: - return TurbulenceData( - data.get("high_avg_yearly_turbulence_per_10cm"), - data.get("low_avg_yearly_turbulence_per_10cm"), - data.get("solar_noon_turbulence_per_10cm"), - data.get("midnight_turbulence_per_10cm"), - ) - - -class TheaterLoader: - THEATER_RESOURCE_DIR = Path("resources/theaters") - - def __init__(self, name: str) -> None: - self.name = name - self.descriptor_path = self.THEATER_RESOURCE_DIR / self.name / "info.yaml" - - @classmethod - def each(cls) -> Iterator[ConflictTheater]: - for theater_dir in cls.THEATER_RESOURCE_DIR.iterdir(): - yield TheaterLoader(theater_dir.name).load() - - @property - def landmap_path(self) -> Path: - return self.descriptor_path.with_name("landmap.p") - - @property - def menu_thumbnail_dcs_relative_path(self) -> Path: - with self.descriptor_path.open(encoding="utf-8") as descriptor_file: - data = yaml.safe_load(descriptor_file) - name = data.get("pydcs_name", data["name"]) - return Path("Mods/terrains") / name / "Theme/icon.png" - - def load(self) -> ConflictTheater: - with self.descriptor_path.open(encoding="utf-8") as descriptor_file: - data = yaml.safe_load(descriptor_file) - return ConflictTheater( - TERRAINS_BY_NAME[data.get("pydcs_name", data["name"])], - load_landmap(self.landmap_path), - datetime.timezone(datetime.timedelta(hours=data["timezone"])), - self._load_seasonal_conditions(data["climate"]), - self._load_daytime_map(data["daytime"]), - ) - - def _load_daytime_map(self, daytime_data: dict[str, list[int]]) -> DaytimeMap: - return DaytimeMap( - dawn=self._load_daytime_range(daytime_data["dawn"]), - day=self._load_daytime_range(daytime_data["day"]), - dusk=self._load_daytime_range(daytime_data["dusk"]), - night=self._load_daytime_range(daytime_data["night"]), - ) - - @staticmethod - def _load_daytime_range( - daytime_range: list[int], - ) -> tuple[datetime.time, datetime.time]: - begin, end = daytime_range - return datetime.time(hour=begin), datetime.time(hour=end) - - def _load_seasonal_conditions( - self, climate_data: dict[str, Any] - ) -> SeasonalConditions: - winter = SeasonData.from_yaml(climate_data["seasons"]["winter"]) - spring = SeasonData.from_yaml(climate_data["seasons"]["spring"]) - summer = SeasonData.from_yaml(climate_data["seasons"]["summer"]) - fall = SeasonData.from_yaml(climate_data["seasons"]["fall"]) - turbulence = TurbulenceData.from_yaml(climate_data["turbulence"]) - if summer.average_pressure is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a summer average pressure" - ) - if summer.average_temperature is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a summer average temperature" - ) - if winter.average_pressure is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a winter average pressure" - ) - if winter.average_temperature is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a winter average temperature" - ) - if turbulence.high_avg_yearly_turbulence_per_10cm is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a yearly average high turbulence" - ) - if turbulence.low_avg_yearly_turbulence_per_10cm is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a yearly average low turbulence" - ) - if turbulence.solar_noon_turbulence_per_10cm is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a solar noon turbulence" - ) - if turbulence.midnight_turbulence_per_10cm is None: - raise RuntimeError( - f"{self.descriptor_path} does not define a midnight turbulence" - ) - return SeasonalConditions( - summer.average_pressure, - winter.average_pressure, - summer.average_temperature, - winter.average_temperature, - climate_data["day_night_temperature_difference"], - turbulence.high_avg_yearly_turbulence_per_10cm, - turbulence.low_avg_yearly_turbulence_per_10cm, - turbulence.solar_noon_turbulence_per_10cm, - turbulence.midnight_turbulence_per_10cm, - { - Season.Winter: winter.weather, - Season.Spring: spring.weather, - Season.Summer: summer.weather, - Season.Fall: fall.weather, - }, - ) diff --git a/game/theater/transitnetwork.py b/game/theater/transitnetwork.py deleted file mode 100644 index 500bb5540..000000000 --- a/game/theater/transitnetwork.py +++ /dev/null @@ -1,196 +0,0 @@ -from __future__ import annotations - -import heapq -import math -from collections import defaultdict -from dataclasses import dataclass, field -from enum import Enum, auto -from typing import Dict, Iterator, List, Optional, Set, Tuple - -from .conflicttheater import ConflictTheater -from .controlpoint import ControlPoint - - -class NoPathError(RuntimeError): - def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None: - super().__init__(f"Could not reconstruct path to {destination} from {origin}") - - -@dataclass(frozen=True, order=True) -class FrontierNode: - cost: float - point: ControlPoint = field(compare=False) - - -class Frontier: - def __init__(self) -> None: - self.nodes: List[FrontierNode] = [] - - def push(self, poly: ControlPoint, cost: float) -> None: - heapq.heappush(self.nodes, FrontierNode(cost, poly)) - - def pop(self) -> Optional[FrontierNode]: - try: - return heapq.heappop(self.nodes) - except IndexError: - return None - - def __bool__(self) -> bool: - return bool(self.nodes) - - -class TransitConnection(Enum): - Road = auto() - Shipping = auto() - Airlift = auto() - - -class TransitNetwork: - def __init__(self) -> None: - self.nodes: Dict[ - ControlPoint, Dict[ControlPoint, TransitConnection] - ] = defaultdict(dict) - - def has_destinations(self, control_point: ControlPoint) -> bool: - return bool(self.nodes[control_point]) - - def has_link(self, a: ControlPoint, b: ControlPoint) -> bool: - return b in self.nodes[a] - - def link_type(self, a: ControlPoint, b: ControlPoint) -> TransitConnection: - return self.nodes[a][b] - - def link_with( - self, a: ControlPoint, b: ControlPoint, link_type: TransitConnection - ) -> None: - self.nodes[a][b] = link_type - self.nodes[b][a] = link_type - - def link_road(self, a: ControlPoint, b: ControlPoint) -> None: - self.link_with(a, b, TransitConnection.Road) - - def link_shipping(self, a: ControlPoint, b: ControlPoint) -> None: - self.link_with(a, b, TransitConnection.Shipping) - - def link_airport(self, a: ControlPoint, b: ControlPoint) -> None: - self.link_with(a, b, TransitConnection.Airlift) - - def connections_from(self, control_point: ControlPoint) -> Iterator[ControlPoint]: - yield from self.nodes[control_point] - - def cost(self, a: ControlPoint, b: ControlPoint) -> float: - return { - TransitConnection.Road: 1, - TransitConnection.Shipping: 3, - # Set arbitrarily high so that other methods are preferred, but still scaled - # by distance so that when we do need it we still pick the closest airfield. - # The units of distance are meters so there's no risk of these - TransitConnection.Airlift: a.position.distance_to_point(b.position), - }[self.link_type(a, b)] - - def has_path_between( - self, - origin: ControlPoint, - destination: ControlPoint, - seen: Optional[set[ControlPoint]] = None, - ) -> bool: - if seen is None: - seen = set() - seen.add(origin) - for connection in self.connections_from(origin): - if connection in seen: - continue - if connection == destination: - return True - if self.has_path_between(connection, destination, seen): - return True - return False - - def shortest_path_between( - self, origin: ControlPoint, destination: ControlPoint - ) -> list[ControlPoint]: - return self.shortest_path_with_cost(origin, destination)[0] - - def shortest_path_with_cost( - self, origin: ControlPoint, destination: ControlPoint - ) -> Tuple[List[ControlPoint], float]: - if origin not in self.nodes: - raise ValueError(f"{origin} is not in the transit network.") - if destination not in self.nodes: - raise ValueError(f"{destination} is not in the transit network.") - - frontier = Frontier() - frontier.push(origin, 0) - - came_from: Dict[ControlPoint, Optional[ControlPoint]] = {origin: None} - - best_known: Dict[ControlPoint, float] = defaultdict(lambda: math.inf) - best_known[origin] = 0.0 - - while (node := frontier.pop()) is not None: - cost = node.cost - current = node.point - if cost > best_known[current]: - continue - - for neighbor in self.connections_from(current): - new_cost = cost + self.cost(node.point, neighbor) - if new_cost < best_known[neighbor]: - best_known[neighbor] = new_cost - frontier.push(neighbor, new_cost) - came_from[neighbor] = current - - # Reconstruct and reverse the path. - current = destination - path: List[ControlPoint] = [] - while current != origin: - path.append(current) - previous = came_from.get(current) - if previous is None: - raise NoPathError(origin, destination) - current = previous - path.reverse() - return path, best_known[destination] - - -class TransitNetworkBuilder: - def __init__(self, theater: ConflictTheater, for_player: bool) -> None: - self.control_points = list(theater.control_points_for(for_player)) - self.network = TransitNetwork() - self.airports: Set[ControlPoint] = { - cp - for cp in self.control_points - if cp.is_friendly(for_player) and cp.runway_is_operational() - } - - def build(self) -> TransitNetwork: - seen = set() - for control_point in self.control_points: - if control_point not in seen: - seen.add(control_point) - self.add_transit_links(control_point) - return self.network - - def add_transit_links(self, control_point: ControlPoint) -> None: - # Prefer road connections. - for road_connection in control_point.connected_points: - if road_connection.is_friendly_to(control_point): - self.network.link_road(control_point, road_connection) - - # Use sea connections if there's no road or rail connection. - for sea_connection in control_point.shipping_lanes: - if self.network.has_link(control_point, sea_connection): - continue - if sea_connection.is_friendly_to(control_point): - self.network.link_shipping(control_point, sea_connection) - - # And use airports as a last resort. - if control_point in self.airports: - for airport in self.airports: - if control_point == airport: - continue - if self.network.has_link(control_point, airport): - continue - if not airport.is_friendly_to(control_point): - continue - self.network.link_airport(control_point, airport) diff --git a/game/threatzones.py b/game/threatzones.py deleted file mode 100644 index 48c955da7..000000000 --- a/game/threatzones.py +++ /dev/null @@ -1,266 +0,0 @@ -from __future__ import annotations - -from functools import singledispatchmethod -from typing import Iterable, Optional, TYPE_CHECKING, Union - -from dcs.mapping import Point as DcsPoint -from shapely.geometry import ( - LineString, - MultiPolygon, - Point as ShapelyPoint, - Polygon, -) -from shapely.geometry.base import BaseGeometry -from shapely.ops import nearest_points, unary_union - -from game.ato import Flight, FlightWaypoint -from game.ato.closestairfields import ObjectiveDistanceCache -from game.data.doctrine import Doctrine -from game.theater import ( - ConflictTheater, - ControlPoint, - MissionTarget, - TheaterGroundObject, -) -from game.utils import Distance, meters, nautical_miles - -if TYPE_CHECKING: - from game import Game - - -ThreatPoly = Union[MultiPolygon, Polygon] - - -class ThreatZones: - def __init__( - self, - theater: ConflictTheater, - airbases: ThreatPoly, - air_defenses: ThreatPoly, - radar_sam_threats: ThreatPoly, - ) -> None: - self.theater = theater - self.airbases = airbases - self.air_defenses = air_defenses - self.radar_sam_threats = radar_sam_threats - self.all = unary_union([airbases, air_defenses]) - - def closest_boundary(self, point: DcsPoint) -> DcsPoint: - boundary, _ = nearest_points( - self.all.boundary, self.dcs_to_shapely_point(point) - ) - return DcsPoint(boundary.x, boundary.y, self.theater.terrain) - - def distance_to_threat(self, point: DcsPoint) -> Distance: - boundary = self.closest_boundary(point) - return meters(boundary.distance_to_point(point)) - - # Type checking ignored because singledispatchmethod doesn't work with required type - # definitions. The implementation methods are all typed, so should be fine. - @singledispatchmethod - def threatened(self, position) -> bool: # type: ignore - raise NotImplementedError - - @threatened.register - def _threatened_geometry(self, position: BaseGeometry) -> bool: - return self.all.intersects(position) - - @threatened.register - def _threatened_dcs_point(self, position: DcsPoint) -> bool: - return self.all.intersects(self.dcs_to_shapely_point(position)) - - def path_threatened(self, a: DcsPoint, b: DcsPoint) -> bool: - return self.threatened( - LineString([self.dcs_to_shapely_point(a), self.dcs_to_shapely_point(b)]) - ) - - # Type checking ignored because singledispatchmethod doesn't work with required type - # definitions. The implementation methods are all typed, so should be fine. - @singledispatchmethod - def threatened_by_aircraft(self, target) -> bool: # type: ignore - raise NotImplementedError - - @threatened_by_aircraft.register - def _threatened_by_aircraft_geom(self, position: BaseGeometry) -> bool: - return self.airbases.intersects(position) - - @threatened_by_aircraft.register - def _threatened_by_aircraft_flight(self, flight: Flight) -> bool: - return self.threatened_by_aircraft( - LineString((self.dcs_to_shapely_point(p.position) for p in flight.points)) - ) - - @threatened_by_aircraft.register - def _threatened_by_aircraft_mission_target(self, target: MissionTarget) -> bool: - return self.threatened_by_aircraft(self.dcs_to_shapely_point(target.position)) - - def waypoints_threatened_by_aircraft( - self, waypoints: Iterable[FlightWaypoint] - ) -> bool: - return self.threatened_by_aircraft( - LineString((self.dcs_to_shapely_point(p.position) for p in waypoints)) - ) - - # Type checking ignored because singledispatchmethod doesn't work with required type - # definitions. The implementation methods are all typed, so should be fine. - @singledispatchmethod - def threatened_by_air_defense(self, target) -> bool: # type: ignore - raise NotImplementedError - - @threatened_by_air_defense.register - def _threatened_by_air_defense_geom(self, position: BaseGeometry) -> bool: - return self.air_defenses.intersects(position) - - @threatened_by_air_defense.register - def _threatened_by_air_defense_dcs_point(self, position: DcsPoint) -> bool: - return self.threatened_by_air_defense(self.dcs_to_shapely_point(position)) - - @threatened_by_air_defense.register - def _threatened_by_air_defense_flight(self, flight: Flight) -> bool: - return self.threatened_by_air_defense( - LineString((self.dcs_to_shapely_point(p.position) for p in flight.points)) - ) - - @threatened_by_air_defense.register - def _threatened_by_air_defense_mission_target(self, target: MissionTarget) -> bool: - return self.threatened_by_air_defense( - self.dcs_to_shapely_point(target.position) - ) - - # Type checking ignored because singledispatchmethod doesn't work with required type - # definitions. The implementation methods are all typed, so should be fine. - @singledispatchmethod - def threatened_by_radar_sam(self, target) -> bool: # type: ignore - raise NotImplementedError - - @threatened_by_radar_sam.register - def _threatened_by_radar_sam_geom(self, position: BaseGeometry) -> bool: - return self.radar_sam_threats.intersects(position) - - @threatened_by_radar_sam.register - def _threatened_by_radar_sam_flight(self, flight: Flight) -> bool: - return self.threatened_by_radar_sam( - LineString((self.dcs_to_shapely_point(p.position) for p in flight.points)) - ) - - def waypoints_threatened_by_radar_sam( - self, waypoints: Iterable[FlightWaypoint] - ) -> bool: - return self.threatened_by_radar_sam( - LineString((self.dcs_to_shapely_point(p.position) for p in waypoints)) - ) - - @classmethod - def closest_enemy_airbase( - cls, location: ControlPoint, max_distance: Distance - ) -> Optional[ControlPoint]: - airfields = ObjectiveDistanceCache.get_closest_airfields(location) - for airfield in airfields.all_airfields_within(max_distance): - if airfield.captured != location.captured: - return airfield - return None - - @classmethod - def barcap_threat_range( - cls, doctrine: Doctrine, control_point: ControlPoint - ) -> Distance: - cap_threat_range = ( - doctrine.cap.max_distance_from_cp + doctrine.cap.engagement_range - ) - opposing_airfield = cls.closest_enemy_airbase( - control_point, cap_threat_range * 2 - ) - if opposing_airfield is None: - return cap_threat_range - - airfield_distance = meters( - opposing_airfield.position.distance_to_point(control_point.position) - ) - - # BARCAPs should not commit further than halfway to the closest enemy - # airfield (with some breathing room) to avoid those missions becoming - # offensive. For dissimilar doctrines we could weight this so that, as - # an example, modern US goes no closer than 70% of the way to the WW2 - # German base, and the Germans go no closer than 30% of the way to the - # US base, but for now equal weighting is fine. - max_distance = airfield_distance * 0.45 - return min(cap_threat_range, max_distance) - - @classmethod - def for_faction(cls, game: Game, player: bool) -> ThreatZones: - """Generates the threat zones projected by the given coalition. - - Args: - game: The game to generate the threat zone for. - player: True if the coalition projecting the threat zone belongs to - the player. - - Returns: - The threat zones projected by the given coalition. If the threat - zone belongs to the player, it is the zone that will be avoided by - the enemy and vice versa. - """ - air_threats = [] - air_defenses = [] - for cp in game.theater.control_points_for(player): - air_threats.append(cp) - air_defenses.extend([go for go in cp.ground_objects if go.has_aa]) - - return cls.for_threats( - game.theater, game.faction_for(player).doctrine, air_threats, air_defenses - ) - - @classmethod - def for_threats( - cls, - theater: ConflictTheater, - doctrine: Doctrine, - barcap_locations: Iterable[ControlPoint], - air_defenses: Iterable[TheaterGroundObject], - ) -> ThreatZones: - """Generates the threat zones projected by the given locations. - - Args: - theater: The theater the threat zones are in. - doctrine: The doctrine of the owning coalition. - barcap_locations: The locations that will be considered for BARCAP planning. - air_defenses: TGOs that may have air defenses. - - Returns: - The threat zones projected by the given locations. If the threat zone - belongs to the player, it is the zone that will be avoided by the enemy and - vice versa. - """ - air_threats = [] - air_defense_threats = [] - radar_sam_threats = [] - for barcap in barcap_locations: - point = ShapelyPoint(barcap.position.x, barcap.position.y) - cap_threat_range = cls.barcap_threat_range(doctrine, barcap) - air_threats.append(point.buffer(cap_threat_range.meters)) - - for tgo in air_defenses: - for group in tgo.groups: - threat_range = group.max_threat_range() - # Any system with a shorter range than this is not worth - # even avoiding. - if threat_range > nautical_miles(3): - point = ShapelyPoint(tgo.position.x, tgo.position.y) - threat_zone = point.buffer(threat_range.meters) - air_defense_threats.append(threat_zone) - radar_threat_range = group.max_threat_range(radar_only=True) - if radar_threat_range > nautical_miles(3): - point = ShapelyPoint(tgo.position.x, tgo.position.y) - threat_zone = point.buffer(radar_threat_range.meters) - radar_sam_threats.append(threat_zone) - - return ThreatZones( - theater, - airbases=unary_union(air_threats), - air_defenses=unary_union(air_defense_threats), - radar_sam_threats=unary_union(radar_sam_threats), - ) - - @staticmethod - def dcs_to_shapely_point(point: DcsPoint) -> ShapelyPoint: - return ShapelyPoint(point.x, point.y) diff --git a/game/timeofday.py b/game/timeofday.py deleted file mode 100644 index 98ed270cc..000000000 --- a/game/timeofday.py +++ /dev/null @@ -1,10 +0,0 @@ -from __future__ import annotations - -from enum import Enum - - -class TimeOfDay(Enum): - Dawn = "dawn" - Day = "day" - Dusk = "dusk" - Night = "night" diff --git a/game/transfers.py b/game/transfers.py deleted file mode 100644 index 8f8b92be7..000000000 --- a/game/transfers.py +++ /dev/null @@ -1,797 +0,0 @@ -"""Implements support for ground unit transfers between bases. - -Ground units can be transferred between bases via a number of transport methods, and -doing so can take multiple turns. - -There are a few main concepts here: - -* A TransferOrder is a request to move units from one base to another. It is described - by its origin, destination, current position, and contents. TransferOrders persist - across turns, and if no Transport is available to move the units in a given turn it - will have no Transport assigned. -* Transports: A Transport is the planned move of a group of units for a leg of the - journey *this turn*. A Transport has an assigned mode of transportation and has - vehicles assigned to move the units if needed. This might be a Convoy, a CargoShip, or - an Airlift. - -The TransportMap (more accurately, it's subtypes) is responsible for managing the -transports moving from A to B for the turn. Transfers that are moving between A and B -this turn will be added to the TransportMap, which will create a new transport if needed -or add the units to an existing transport if one exists. This allows transfers from -A->B->C and D->B->C to share a transport between B and C. - -AirLifts do not use TransportMap because no merging will take place between orders. It -instead uses AirLiftPlanner to create transport packages. - -PendingTransfers manages all the incomplete transfer orders for the game. New transfer -orders are registered with PendingTransfers and it is responsible for allocating -transports and processing the turn's transit actions. - -Routing is handled by TransitNetwork. -""" -from __future__ import annotations - -import logging -import math -from collections import defaultdict -from dataclasses import dataclass, field -from datetime import datetime -from functools import singledispatchmethod -from typing import Generic, Iterator, List, Optional, Sequence, TYPE_CHECKING, TypeVar - -from dcs.mapping import Point - -from game.ato.closestairfields import ObjectiveDistanceCache -from game.ato.flight import Flight -from game.ato.flighttype import FlightType -from game.ato.package import Package -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.naming import namegen -from game.procurement import AircraftProcurementRequest -from game.theater import ControlPoint, MissionTarget -from game.theater.transitnetwork import ( - TransitConnection, - TransitNetwork, -) -from game.utils import meters, nautical_miles - -if TYPE_CHECKING: - from game import Game - from game.squadrons import Squadron - - -class Transport: - def __init__(self, destination: ControlPoint): - self.destination = destination - - def find_escape_route(self) -> Optional[ControlPoint]: - raise NotImplementedError - - def description(self) -> str: - raise NotImplementedError - - -@dataclass -class TransferOrder: - """The base type of all transfer orders. - - A transfer order can transfer multiple units of multiple types. - """ - - #: The location the units are transferring from. - origin: ControlPoint - - #: The location the units are transferring to. - destination: ControlPoint - - #: The current position of the group being transferred. Groups may make multiple - #: stops and can switch transport modes before reaching their destination. - position: ControlPoint = field(init=False) - - #: True if the transfer order belongs to the player. - player: bool = field(init=False) - - #: The units being transferred. - units: dict[GroundUnitType, int] - - transport: Optional[Transport] = field(default=None) - - request_airflift: bool = field(default=False) - - def __str__(self) -> str: - """Returns the text that should be displayed for the transfer.""" - count = self.size - origin = self.origin.name - destination = self.destination.name - description = "Transfer" if self.player else "Enemy transfer" - return f"{description} of {count} units from {origin} to {destination}" - - def __post_init__(self) -> None: - self.position = self.origin - self.player = self.origin.is_friendly(to_player=True) - - @property - def description(self) -> str: - if self.transport is None: - return "No transports available" - return self.transport.description() - - def kill_all(self) -> None: - self.units.clear() - - def kill_unit(self, unit_type: GroundUnitType) -> None: - self.take_units(unit_type, 1) - - def take_units(self, unit_type: GroundUnitType, count: int) -> None: - """Removes units from the transfer without returning them to inventory. - - The caller takes ownership of the units. - """ - if unit_type not in self.units or self.units[unit_type] < count: - raise KeyError(f"{self} has fewer than {count} {unit_type} remaining") - - self.units[unit_type] -= count - if not self.units[unit_type]: - del self.units[unit_type] - - @property - def size(self) -> int: - return sum(self.units.values()) - - def iter_units(self) -> Iterator[GroundUnitType]: - for unit_type, count in self.units.items(): - for _ in range(count): - yield unit_type - - @property - def completed(self) -> bool: - return self.destination == self.position or not self.size - - def disband_at(self, location: ControlPoint) -> None: - logging.info(f"Units halting at {location}.") - location.base.commission_units(self.units) - self.units.clear() - - @property - def next_stop(self) -> ControlPoint: - if self.transport is None: - raise RuntimeError( - "TransferOrder.next_stop called with no transport assigned" - ) - return self.transport.destination - - def find_escape_route(self) -> Optional[ControlPoint]: - if self.transport is not None: - return self.transport.find_escape_route() - return None - - def disband(self) -> None: - """ - Disbands the specific transfer at the current position if friendly, at a - possible escape route or kills all units if none is possible - """ - if self.position.is_friendly(self.player): - self.disband_at(self.position) - elif (escape_route := self.find_escape_route()) is not None: - self.disband_at(escape_route) - else: - logging.info( - f"No escape route available. Units were surrounded and destroyed " - "during transfer." - ) - self.kill_all() - - def is_completable(self, network: TransitNetwork) -> bool: - """ - Checks if the transfer can be completed with the current theater state / transit - network to ensure that there is possible route between the current position and - the planned destination. This also ensures that the points are friendly. - """ - if self.transport is None: - # Check if unplanned transfers could be completed - if not self.position.is_friendly(self.player): - logging.info( - f"Current position ({self.position}) " - f"of the halting transfer was captured." - ) - return False - if not network.has_path_between(self.position, self.destination): - logging.info( - f"Destination of transfer ({self.destination}) " - f"can not be reached anymore." - ) - return False - - if self.transport is not None and not self.next_stop.is_friendly(self.player): - # check if already proceeding transfers can reach the next stop - logging.info( - f"The next stop of the transfer ({self.next_stop}) " - f"was captured while transfer was on route." - ) - return False - - return True - - def proceed(self) -> None: - """ - Let the transfer proceed to the next stop and disbands it if the next stop - is the destination - """ - if self.transport is None: - return - - self.position = self.next_stop - self.transport = None - - if self.completed: - self.disband_at(self.position) - - -class Airlift(Transport): - """A transfer order that moves units by cargo planes and helicopters.""" - - def __init__( - self, transfer: TransferOrder, flight: Flight, next_stop: ControlPoint - ) -> None: - super().__init__(next_stop) - self.transfer = transfer - self.flight = flight - - @property - def units(self) -> dict[GroundUnitType, int]: - return self.transfer.units - - @property - def player_owned(self) -> bool: - return self.transfer.player - - def find_escape_route(self) -> Optional[ControlPoint]: - # TODO: Move units to closest base. - return None - - def description(self) -> str: - return ( - f"Being airlifted from {self.transfer.position} to {self.destination} by " - f"{self.flight}" - ) - - -class AirliftPlanner: - #: Maximum range from for any link in the route of takeoff, pickup, dropoff, and RTB - #: for a helicopter to be considered for airlift. Total route length is not - #: considered because the helicopter can refuel at each stop. Cargo planes have no - #: maximum range. - HELO_MAX_RANGE = nautical_miles(100) - - def __init__( - self, game: Game, transfer: TransferOrder, next_stop: ControlPoint - ) -> None: - self.game = game - self.transfer = transfer - self.next_stop = next_stop - self.for_player = transfer.destination.captured - self.package = Package(next_stop, game.db.flights, auto_asap=True) - - def compatible_with_mission( - self, unit_type: AircraftType, airfield: ControlPoint - ) -> bool: - if not unit_type.capable_of(FlightType.TRANSPORT): - return False - if not self.transfer.origin.can_operate(unit_type): - return False - if not self.next_stop.can_operate(unit_type): - return False - - # Cargo planes have no maximum range. - if not unit_type.dcs_unit_type.helicopter: - return True - - # A helicopter that is transport capable and able to operate at both bases. Need - # to check that no leg of the journey exceeds the maximum range. This doesn't - # account for any routing around threats that might take place, but it's close - # enough. - - home = airfield.position - pickup = self.transfer.position.position - drop_off = self.transfer.position.position - if meters(home.distance_to_point(pickup)) > self.HELO_MAX_RANGE: - return False - - if meters(pickup.distance_to_point(drop_off)) > self.HELO_MAX_RANGE: - return False - - if meters(drop_off.distance_to_point(home)) > self.HELO_MAX_RANGE: - return False - - return True - - def create_package_for_airlift(self, now: datetime) -> None: - distance_cache = ObjectiveDistanceCache.get_closest_airfields( - self.transfer.position - ) - air_wing = self.game.air_wing_for(self.for_player) - for cp in distance_cache.closest_airfields: - if cp.captured != self.for_player: - continue - - squadrons = air_wing.auto_assignable_for_task_at(FlightType.TRANSPORT, cp) - for squadron in squadrons: - if self.compatible_with_mission(squadron.aircraft, cp): - while ( - squadron.untasked_aircraft - and squadron.has_available_pilots - and self.transfer.transport is None - ): - self.create_airlift_flight(squadron) - if self.package.flights: - self.package.set_tot_asap(now) - self.game.ato_for(self.for_player).add_package(self.package) - - def create_airlift_flight(self, squadron: Squadron) -> int: - available_aircraft = squadron.untasked_aircraft - capacity_each = 1 if squadron.aircraft.dcs_unit_type.helicopter else 2 - required = math.ceil(self.transfer.size / capacity_each) - flight_size = min( - required, - available_aircraft, - squadron.aircraft.dcs_unit_type.group_size_max, - ) - # TODO: Use number_of_available_pilots directly once feature flag is gone. - # The number of currently available pilots is not relevant when pilot limits - # are disabled. - if not squadron.can_fulfill_flight(flight_size): - flight_size = squadron.max_fulfillable_aircraft - capacity = flight_size * capacity_each - - if capacity < self.transfer.size: - transfer = self.game.coalition_for( - self.for_player - ).transfers.split_transfer(self.transfer, capacity) - else: - transfer = self.transfer - - start_type = squadron.location.required_aircraft_start_type - if start_type is None: - start_type = self.game.settings.default_start_type - - flight = Flight( - self.package, - self.game.country_for(squadron.player), - squadron, - flight_size, - FlightType.TRANSPORT, - start_type, - divert=None, - cargo=transfer, - ) - - transport = Airlift(transfer, flight, self.next_stop) - transfer.transport = transport - - self.package.add_flight(flight) - flight.recreate_flight_plan() - return flight_size - - -class MultiGroupTransport(MissionTarget, Transport): - def __init__( - self, name: str, origin: ControlPoint, destination: ControlPoint - ) -> None: - MissionTarget.__init__(self, name, origin.position) - Transport.__init__(self, destination) - self.origin = origin - self.transfers: List[TransferOrder] = [] - - def is_friendly(self, to_player: bool) -> bool: - return self.origin.captured - - def add_units(self, transfer: TransferOrder) -> None: - self.transfers.append(transfer) - transfer.transport = self - - def remove_units(self, transfer: TransferOrder) -> None: - transfer.transport = None - self.transfers.remove(transfer) - - def kill_unit(self, unit_type: GroundUnitType) -> None: - for transfer in self.transfers: - try: - transfer.kill_unit(unit_type) - return - except KeyError: - pass - raise KeyError - - def kill_all(self) -> None: - for transfer in self.transfers: - transfer.kill_all() - - def disband(self) -> None: - for transfer in list(self.transfers): - self.remove_units(transfer) - self.transfers.clear() - - @property - def size(self) -> int: - return sum(t.size for t in self.transfers) - - @property - def units(self) -> dict[GroundUnitType, int]: - units: dict[GroundUnitType, int] = defaultdict(int) - for transfer in self.transfers: - for unit_type, count in transfer.units.items(): - units[unit_type] += count - return units - - def iter_units(self) -> Iterator[GroundUnitType]: - for unit_type, count in self.units.items(): - for _ in range(count): - yield unit_type - - @property - def player_owned(self) -> bool: - return self.origin.captured - - def find_escape_route(self) -> Optional[ControlPoint]: - raise NotImplementedError - - def description(self) -> str: - raise NotImplementedError - - -class Convoy(MultiGroupTransport): - def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None: - super().__init__(namegen.next_convoy_name(), origin, destination) - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - if self.is_friendly(for_player): - return - - yield FlightType.BAI - yield from super().mission_types(for_player) - - @property - def route_start(self) -> Point: - return self.origin.convoy_origin_for(self.destination) - - @property - def route_end(self) -> Point: - return self.destination.convoy_origin_for(self.origin) - - def description(self) -> str: - return f"In a convoy from {self.origin} to {self.destination}" - - def find_escape_route(self) -> Optional[ControlPoint]: - return None - - -class CargoShip(MultiGroupTransport): - def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None: - super().__init__(namegen.next_cargo_ship_name(), origin, destination) - - def mission_types(self, for_player: bool) -> Iterator[FlightType]: - if self.is_friendly(for_player): - return - - yield FlightType.ANTISHIP - yield from super().mission_types(for_player) - - @property - def route(self) -> Sequence[Point]: - return self.origin.shipping_lanes[self.destination] - - def description(self) -> str: - return f"On a ship from {self.origin} to {self.destination}" - - def find_escape_route(self) -> Optional[ControlPoint]: - return None - - -TransportType = TypeVar("TransportType", bound=MultiGroupTransport) - - -class TransportMap(Generic[TransportType]): - def __init__(self) -> None: - # Dict of origin -> destination -> transport. - self.transports: dict[ - ControlPoint, dict[ControlPoint, TransportType] - ] = defaultdict(dict) - - def create_transport( - self, origin: ControlPoint, destination: ControlPoint - ) -> TransportType: - raise NotImplementedError - - def transport_exists(self, origin: ControlPoint, destination: ControlPoint) -> bool: - return destination in self.transports[origin] - - def find_transport( - self, origin: ControlPoint, destination: ControlPoint - ) -> Optional[TransportType]: - return self.transports[origin].get(destination) - - def find_or_create_transport( - self, origin: ControlPoint, destination: ControlPoint - ) -> TransportType: - transport = self.find_transport(origin, destination) - if transport is None: - transport = self.create_transport(origin, destination) - self.transports[origin][destination] = transport - return transport - - def departing_from(self, origin: ControlPoint) -> Iterator[TransportType]: - yield from self.transports[origin].values() - - def travelling_to(self, destination: ControlPoint) -> Iterator[TransportType]: - for destination_dict in self.transports.values(): - if destination in destination_dict: - yield destination_dict[destination] - - def disband_transport(self, transport: TransportType) -> None: - transport.disband() - del self.transports[transport.origin][transport.destination] - - def add(self, transfer: TransferOrder, next_stop: ControlPoint) -> None: - self.find_or_create_transport(transfer.position, next_stop).add_units(transfer) - - def remove(self, transport: TransportType, transfer: TransferOrder) -> None: - transport.remove_units(transfer) - if not transport.transfers: - self.disband_transport(transport) - - def disband_all(self) -> None: - for transport in list(self): - self.disband_transport(transport) - - def __iter__(self) -> Iterator[TransportType]: - for destination_dict in self.transports.values(): - yield from destination_dict.values() - - -class ConvoyMap(TransportMap[Convoy]): - def create_transport( - self, origin: ControlPoint, destination: ControlPoint - ) -> Convoy: - return Convoy(origin, destination) - - -class CargoShipMap(TransportMap[CargoShip]): - def create_transport( - self, origin: ControlPoint, destination: ControlPoint - ) -> CargoShip: - return CargoShip(origin, destination) - - -class PendingTransfers: - def __init__(self, game: Game, player: bool) -> None: - self.game = game - self.player = player - self.convoys = ConvoyMap() - self.cargo_ships = CargoShipMap() - self.pending_transfers: List[TransferOrder] = [] - - def __iter__(self) -> Iterator[TransferOrder]: - yield from self.pending_transfers - - @property - def pending_transfer_count(self) -> int: - return len(self.pending_transfers) - - def transfer_at_index(self, index: int) -> TransferOrder: - return self.pending_transfers[index] - - def index_of_transfer(self, transfer: TransferOrder) -> int: - return self.pending_transfers.index(transfer) - - def network_for(self, control_point: ControlPoint) -> TransitNetwork: - return self.game.transit_network_for(control_point.captured) - - def arrange_transport(self, transfer: TransferOrder, now: datetime) -> None: - network = self.network_for(transfer.position) - path = network.shortest_path_between(transfer.position, transfer.destination) - next_stop = path[0] - if not transfer.request_airflift: - if ( - network.link_type(transfer.position, next_stop) - == TransitConnection.Road - ): - return self.convoys.add(transfer, next_stop) - elif ( - network.link_type(transfer.position, next_stop) - == TransitConnection.Shipping - ): - return self.cargo_ships.add(transfer, next_stop) - AirliftPlanner(self.game, transfer, next_stop).create_package_for_airlift(now) - - def new_transfer(self, transfer: TransferOrder, now: datetime) -> None: - transfer.origin.base.commit_losses(transfer.units) - self.pending_transfers.append(transfer) - self.arrange_transport(transfer, now) - - def split_transfer(self, transfer: TransferOrder, size: int) -> TransferOrder: - """Creates a smaller transfer that is a subset of the original.""" - if transfer.size <= size: - raise ValueError - - units = {} - # If one type of unit is zeroed but there are still other units to check in the - # dict, the dict will have changed size during iteration. Iterate on a copy of - # the dict instead. - for unit_type, remaining in dict(transfer.units).items(): - take = min(remaining, size) - size -= take - transfer.take_units(unit_type, take) - units[unit_type] = take - if not size: - break - new_transfer = TransferOrder(transfer.origin, transfer.destination, units) - self.pending_transfers.append(new_transfer) - return new_transfer - - # Type checking ignored because singledispatchmethod doesn't work with required type - # definitions. The implementation methods are all typed, so should be fine. - @singledispatchmethod - def cancel_transport( # type: ignore - self, - transport, - transfer: TransferOrder, - ) -> None: - pass - - @cancel_transport.register - def _cancel_transport_air( - self, transport: Airlift, _transfer: TransferOrder - ) -> None: - flight = transport.flight - flight.package.remove_flight(flight) - if not flight.package.flights: - self.game.ato_for(self.player).remove_package(flight.package) - - @cancel_transport.register - def _cancel_transport_convoy( - self, transport: Convoy, transfer: TransferOrder - ) -> None: - self.convoys.remove(transport, transfer) - - @cancel_transport.register - def _cancel_transport_cargo_ship( - self, transport: CargoShip, transfer: TransferOrder - ) -> None: - self.cargo_ships.remove(transport, transfer) - - def cancel_transfer(self, transfer: TransferOrder) -> None: - if transfer.transport is not None: - self.cancel_transport(transfer.transport, transfer) - self.pending_transfers.remove(transfer) - transfer.origin.base.commission_units(transfer.units) - - def perform_transfers(self) -> None: - """ - Performs completable transfers from the list of pending transfers and adds - uncompleted transfers which are en route back to the list of pending transfers. - Disbands all convoys and cargo ships - """ - self.disband_uncompletable_transfers() - incomplete = [] - for transfer in self.pending_transfers: - transfer.proceed() - if not transfer.completed: - incomplete.append(transfer) - self.pending_transfers = incomplete - self.convoys.disband_all() - self.cargo_ships.disband_all() - - def plan_transports(self, now: datetime) -> None: - """ - Plan transports for all pending and completable transfers which don't have a - transport assigned already. This calculates the shortest path between current - position and destination on every execution to ensure the route is adopted to - recent changes in the theater state / transit network. - """ - self.disband_uncompletable_transfers() - for transfer in self.pending_transfers: - if transfer.transport is None: - self.arrange_transport(transfer, now) - - def disband_uncompletable_transfers(self) -> None: - """ - Disbands all transfers from the list of pending_transfers which can not be - completed anymore because the theater state changed or the transit network does - not allow a route to the destination anymore - """ - completable_transfers = [] - for transfer in self.pending_transfers: - if not transfer.is_completable(self.network_for(transfer.position)): - if transfer.transport: - self.cancel_transport(transfer.transport, transfer) - transfer.disband() - else: - completable_transfers.append(transfer) - self.pending_transfers = completable_transfers - - def order_airlift_assets(self) -> None: - for control_point in self.game.theater.control_points_for(self.player): - if self.game.air_wing_for(control_point.captured).can_auto_plan( - FlightType.TRANSPORT - ): - self.order_airlift_assets_at(control_point) - - def desired_airlift_capacity(self, control_point: ControlPoint) -> int: - if control_point.has_factory: - is_major_hub = control_point.total_aircraft_parking > 0 - # Check if there is a CP which is only reachable via Airlift - transit_network = self.network_for(control_point) - for cp in self.game.theater.control_points_for(self.player): - # check if the CP has no factory, is reachable from the current - # position and can only be reached with airlift connections - if ( - cp.can_deploy_ground_units - and not cp.has_factory - and transit_network.has_link(control_point, cp) - and not any( - link_type - for link, link_type in transit_network.nodes[cp].items() - if not link_type == TransitConnection.Airlift - ) - ): - return 4 - - if ( - is_major_hub - and cp.has_factory - and cp.total_aircraft_parking > control_point.total_aircraft_parking - ): - is_major_hub = False - - if is_major_hub: - # If the current CP is a major hub keep always 2 planes on reserve - return 2 - - return 0 - - @staticmethod - def current_airlift_capacity(control_point: ControlPoint) -> int: - return sum( - s.owned_aircraft - for s in control_point.squadrons - if s.can_auto_assign(FlightType.TRANSPORT) - ) - - def order_airlift_assets_at(self, control_point: ControlPoint) -> None: - unclaimed_parking = control_point.unclaimed_parking() - # Buy a maximum of unclaimed_parking only to prevent that aircraft procurement - # take place at another base - gap = min( - [ - self.desired_airlift_capacity(control_point) - - self.current_airlift_capacity(control_point), - unclaimed_parking, - ] - ) - - if gap <= 0: - return - - if gap % 2: - # Always buy in pairs since we're not trying to fill odd squadrons. Purely - # aesthetic. - gap += 1 - - if gap > unclaimed_parking: - # Prevent to buy more aircraft than possible - return - - self.game.coalition_for(self.player).add_procurement_request( - AircraftProcurementRequest(control_point, FlightType.TRANSPORT, gap) - ) - - def transfer_for_flight(self, flight: Flight) -> Optional[TransferOrder]: - for transfer in self.pending_transfers: - if transfer.transport is None or not isinstance( - transfer.transport, Airlift - ): - continue - if transfer.transport.flight == flight: - return transfer - return None diff --git a/game/turnstate.py b/game/turnstate.py deleted file mode 100644 index 80811f6dd..000000000 --- a/game/turnstate.py +++ /dev/null @@ -1,9 +0,0 @@ -from __future__ import annotations - -from enum import Enum - - -class TurnState(Enum): - WIN = 0 - LOSS = 1 - CONTINUE = 2 diff --git a/game/typeguard.py b/game/typeguard.py deleted file mode 100644 index eac463acf..000000000 --- a/game/typeguard.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import annotations - -from typing import Callable, TypeGuard, TypeVar - -SelfT = TypeVar("SelfT") -BaseT = TypeVar("BaseT") -GuardT = TypeVar("GuardT") - - -def self_type_guard( - f: Callable[[SelfT, BaseT], TypeGuard[GuardT]] -) -> Callable[[SelfT, BaseT], TypeGuard[GuardT]]: - def decorator(s: SelfT, arg: BaseT) -> TypeGuard[GuardT]: - if id(s) != id(arg): - raise ValueError( - "self type guards must be called with self as the argument" - ) - return f(s, arg) - - return decorator diff --git a/game/unitmap.py b/game/unitmap.py deleted file mode 100644 index 9ad12ec29..000000000 --- a/game/unitmap.py +++ /dev/null @@ -1,183 +0,0 @@ -"""Maps generated units back to their Liberation types.""" -from __future__ import annotations - -import itertools -import math -from dataclasses import dataclass -from typing import Dict, Optional, Any, TYPE_CHECKING - -from dcs.triggers import TriggerZone -from dcs.unit import Unit -from dcs.unitgroup import FlyingGroup, VehicleGroup, ShipGroup - -from game.ato.flight import Flight -from game.dcs.groundunittype import GroundUnitType -from game.squadrons import Pilot -from game.theater import Airfield, ControlPoint, TheaterUnit -from game.theater.theatergroup import SceneryUnit - -if TYPE_CHECKING: - from game.transfers import CargoShip, Convoy, TransferOrder - - -@dataclass(frozen=True) -class FlyingUnit: - flight: Flight - pilot: Optional[Pilot] - - -@dataclass(frozen=True) -class FrontLineUnit: - unit_type: GroundUnitType - origin: ControlPoint - - -@dataclass(frozen=True) -class TheaterUnitMapping: - dcs_group_id: int - theater_unit: TheaterUnit - dcs_unit: Unit - - -@dataclass(frozen=True) -class SceneryObjectMapping: - ground_unit: TheaterUnit - trigger_zone: TriggerZone - - -@dataclass(frozen=True) -class ConvoyUnit: - unit_type: GroundUnitType - convoy: Convoy - - -@dataclass(frozen=True) -class AirliftUnits: - cargo: tuple[GroundUnitType, ...] - transfer: TransferOrder - - -class UnitMap: - def __init__(self) -> None: - self.aircraft: Dict[str, FlyingUnit] = {} - self.airfields: Dict[str, Airfield] = {} - self.front_line_units: Dict[str, FrontLineUnit] = {} - self.theater_objects: Dict[str, TheaterUnitMapping] = {} - self.scenery_objects: Dict[str, SceneryObjectMapping] = {} - self.convoys: Dict[str, ConvoyUnit] = {} - self.cargo_ships: Dict[str, CargoShip] = {} - self.airlifts: Dict[str, AirliftUnits] = {} - - def add_aircraft(self, group: FlyingGroup[Any], flight: Flight) -> None: - for pilot, unit in zip(flight.roster.iter_pilots(), group.units): - # The actual name is a String (the pydcs translatable string), which - # doesn't define __eq__. - name = str(unit.name) - if name in self.aircraft: - raise RuntimeError(f"Duplicate unit name: {name}") - self.aircraft[name] = FlyingUnit(flight, pilot) - if flight.cargo is not None: - self.add_airlift_units(group, flight.cargo) - - def flight(self, unit_name: str) -> Optional[FlyingUnit]: - return self.aircraft.get(unit_name, None) - - def add_airfield(self, airfield: Airfield) -> None: - if airfield.name in self.airfields: - raise RuntimeError(f"Duplicate airfield: {airfield.name}") - self.airfields[airfield.name] = airfield - - def airfield(self, name: str) -> Optional[Airfield]: - return self.airfields.get(name, None) - - def add_front_line_units( - self, group: VehicleGroup, origin: ControlPoint, unit_type: GroundUnitType - ) -> None: - for unit in group.units: - # The actual name is a String (the pydcs translatable string), which - # doesn't define __eq__. - name = str(unit.name) - if name in self.front_line_units: - raise RuntimeError(f"Duplicate front line unit: {name}") - self.front_line_units[name] = FrontLineUnit(unit_type, origin) - - def front_line_unit(self, name: str) -> Optional[FrontLineUnit]: - return self.front_line_units.get(name, None) - - def add_theater_unit_mapping( - self, dcs_group_id: int, theater_unit: TheaterUnit, dcs_unit: Unit - ) -> None: - # Deaths for units at TGOs are recorded in the corresponding GroundUnit within - # the GroundGroup, so we have to match the dcs unit with the liberation unit - name = str(dcs_unit.name) - if name in self.theater_objects: - raise RuntimeError(f"Duplicate TGO unit: {name}") - self.theater_objects[name] = TheaterUnitMapping( - dcs_group_id, theater_unit, dcs_unit - ) - - def theater_units(self, name: str) -> Optional[TheaterUnitMapping]: - return self.theater_objects.get(name, None) - - def add_convoy_units(self, group: VehicleGroup, convoy: Convoy) -> None: - for unit, unit_type in zip(group.units, convoy.iter_units()): - # The actual name is a String (the pydcs translatable string), which - # doesn't define __eq__. - name = str(unit.name) - if name in self.convoys: - raise RuntimeError(f"Duplicate convoy unit: {name}") - self.convoys[name] = ConvoyUnit(unit_type, convoy) - - def convoy_unit(self, name: str) -> Optional[ConvoyUnit]: - return self.convoys.get(name, None) - - def add_cargo_ship(self, group: ShipGroup, ship: CargoShip) -> None: - if len(group.units) > 1: - # Cargo ship "groups" are single units. Killing the one ship kills the whole - # transfer. If we ever want to add escorts or create multiple cargo ships in - # a convoy of ships that logic needs to change. - raise ValueError("Expected cargo ship to be a single unit group.") - unit = group.units[0] - # The actual name is a String (the pydcs translatable string), which - # doesn't define __eq__. - name = str(unit.name) - if name in self.cargo_ships: - raise RuntimeError(f"Duplicate cargo ship: {name}") - self.cargo_ships[name] = ship - - def cargo_ship(self, name: str) -> Optional[CargoShip]: - return self.cargo_ships.get(name, None) - - def add_airlift_units( - self, group: FlyingGroup[Any], transfer: TransferOrder - ) -> None: - capacity_each = math.ceil(transfer.size / len(group.units)) - for idx, transport in enumerate(group.units): - # Slice the units in groups based on the capacity of each unit. Cargo is - # assigned arbitrarily to units in the order of the group. The last unit in - # the group will receive a partial load if there is not enough cargo to fill - # every transport. - base_idx = idx * capacity_each - cargo = tuple( - itertools.islice( - transfer.iter_units(), base_idx, base_idx + capacity_each - ) - ) - # The actual name is a String (the pydcs translatable string), which - # doesn't define __eq__. - name = str(transport.name) - if name in self.airlifts: - raise RuntimeError(f"Duplicate airlift unit: {name}") - self.airlifts[name] = AirliftUnits(cargo, transfer) - - def airlift_unit(self, name: str) -> Optional[AirliftUnits]: - return self.airlifts.get(name, None) - - def add_scenery(self, scenery_unit: SceneryUnit, trigger_zone: TriggerZone) -> None: - name = str(trigger_zone.name) - if name in self.scenery_objects: - raise RuntimeError(f"Duplicate scenery object {name} (TriggerZone)") - self.scenery_objects[name] = SceneryObjectMapping(scenery_unit, trigger_zone) - - def scenery_object(self, name: str) -> Optional[SceneryObjectMapping]: - return self.scenery_objects.get(name, None) diff --git a/game/utils.py b/game/utils.py deleted file mode 100644 index 43c750d32..000000000 --- a/game/utils.py +++ /dev/null @@ -1,483 +0,0 @@ -from __future__ import annotations - -import itertools -import math -import os -import random -from abc import ABC, abstractmethod -from collections.abc import Iterable -from dataclasses import dataclass -from typing import TypeVar, Union - -from dcs import Point -from shapely.geometry import Point as ShapelyPoint - -METERS_TO_FEET = 3.28084 -FEET_TO_METERS = 1 / METERS_TO_FEET -NM_TO_METERS = 1852 -METERS_TO_NM = 1 / NM_TO_METERS -MILES_TO_METERS = 1609.34 -METERS_TO_MILES = 1 / MILES_TO_METERS - -KNOTS_TO_KPH = 1.852 -KPH_TO_KNOTS = 1 / KNOTS_TO_KPH -MS_TO_KPH = 3.6 -KPH_TO_MS = 1 / MS_TO_KPH -KPH_TO_MPH = 0.621371 -MPH_TO_KPH = 1 / KPH_TO_MPH - -INHG_TO_HPA = 33.86389 -INHG_TO_MMHG = 25.400002776728 - -LBS_TO_KG = 0.453592 -KG_TO_LBS = 1 / LBS_TO_KG - - -class UnitSystem(ABC): - @abstractmethod - def distance_short(self, dist: Distance) -> float: - pass - - @abstractmethod - def distance_long(self, dist: Distance) -> float: - pass - - @property - @abstractmethod - def distance_short_uom(self) -> str: - pass - - @property - @abstractmethod - def distance_long_uom(self) -> str: - pass - - @abstractmethod - def speed(self, speed: Speed) -> float: - pass - - @property - @abstractmethod - def speed_uom(self) -> str: - pass - - @abstractmethod - def mass(self, mass: Mass) -> float: - pass - - @property - @abstractmethod - def mass_uom(self) -> str: - pass - - -class NauticalUnits(UnitSystem): - def distance_short(self, dist: Distance) -> float: - return dist.feet - - def distance_long(self, dist: Distance) -> float: - return dist.nautical_miles - - @property - def distance_short_uom(self) -> str: - return "ft" - - @property - def distance_long_uom(self) -> str: - return "nm" - - def speed(self, speed: Speed) -> float: - return speed.knots - - @property - def speed_uom(self) -> str: - return "kt" - - def mass(self, mass: Mass) -> float: - return mass.pounds - - @property - def mass_uom(self) -> str: - return "lb" - - -class MetricUnits(UnitSystem): - def distance_short(self, dist: Distance) -> float: - return dist.meters - - def distance_long(self, dist: Distance) -> float: - return dist.kilometers - - @property - def distance_short_uom(self) -> str: - return "m" - - @property - def distance_long_uom(self) -> str: - return "km" - - def speed(self, speed: Speed) -> float: - return speed.kph - - @property - def speed_uom(self) -> str: - return "kph" - - def mass(self, mass: Mass) -> float: - return mass.kgs - - @property - def mass_uom(self) -> str: - return "kg" - - -class ImperialUnits(UnitSystem): - def distance_short(self, dist: Distance) -> float: - return dist.feet - - def distance_long(self, dist: Distance) -> float: - return dist.miles - - @property - def distance_short_uom(self) -> str: - return "ft" - - @property - def distance_long_uom(self) -> str: - return "m" - - def speed(self, speed: Speed) -> float: - return speed.mph - - @property - def speed_uom(self) -> str: - return "mph" - - def mass(self, mass: Mass) -> float: - return mass.pounds - - @property - def mass_uom(self) -> str: - return "lb" - - -@dataclass(frozen=True) -class Distance: - distance_in_meters: float - - @property - def feet(self) -> float: - return self.distance_in_meters * METERS_TO_FEET - - @property - def meters(self) -> float: - return self.distance_in_meters - - @property - def nautical_miles(self) -> float: - return self.distance_in_meters * METERS_TO_NM - - @property - def kilometers(self) -> float: - return self.distance_in_meters / 1000 - - @property - def miles(self) -> float: - return self.distance_in_meters * METERS_TO_MILES - - @classmethod - def from_feet(cls, value: float) -> Distance: - return cls(value * FEET_TO_METERS) - - @classmethod - def from_meters(cls, value: float) -> Distance: - return cls(value) - - @classmethod - def from_nautical_miles(cls, value: float) -> Distance: - return cls(value * NM_TO_METERS) - - @classmethod - def inf(cls) -> Distance: - return cls.from_meters(math.inf) - - def __str__(self) -> str: - return f"{self.distance_in_meters} meters" - - def __add__(self, other: Distance) -> Distance: - return meters(self.meters + other.meters) - - def __sub__(self, other: Distance) -> Distance: - return meters(self.meters - other.meters) - - def __mul__(self, other: Union[float, int]) -> Distance: - return meters(self.meters * other) - - __rmul__ = __mul__ - - def __truediv__(self, other: Union[float, int]) -> Distance: - return meters(self.meters / other) - - def __floordiv__(self, other: Union[float, int]) -> Distance: - return meters(self.meters // other) - - def __bool__(self) -> bool: - return not math.isclose(self.meters, 0.0) - - def __lt__(self, other: Distance) -> bool: - return self.meters < other.meters - - def __le__(self, other: Distance) -> bool: - return self.meters <= other.meters - - def __gt__(self, other: Distance) -> bool: - return self.meters > other.meters - - def __ge__(self, other: Distance) -> bool: - return self.meters >= other.meters - - -def feet(value: float) -> Distance: - return Distance.from_feet(value) - - -def meters(value: float) -> Distance: - return Distance.from_meters(value) - - -def nautical_miles(value: float) -> Distance: - return Distance.from_nautical_miles(value) - - -@dataclass(frozen=True, order=True) -class Speed: - speed_in_kph: float - - @property - def knots(self) -> float: - return self.speed_in_kph * KPH_TO_KNOTS - - @property - def kph(self) -> float: - return self.speed_in_kph - - @property - def meters_per_second(self) -> float: - return self.speed_in_kph * KPH_TO_MS - - @property - def mph(self) -> float: - return self.speed_in_kph * KPH_TO_MPH - - def mach(self, altitude: Distance = meters(0)) -> float: - c_sound = mach(1, altitude) - return self.speed_in_kph / c_sound.kph - - @classmethod - def from_knots(cls, value: float) -> Speed: - return cls(value * KNOTS_TO_KPH) - - @classmethod - def from_kph(cls, value: float) -> Speed: - return cls(value) - - @classmethod - def from_meters_per_second(cls, value: float) -> Speed: - return cls(value * MS_TO_KPH) - - @classmethod - def from_mach(cls, value: float, altitude: Distance) -> Speed: - # https://www.grc.nasa.gov/WWW/K-12/airplane/atmos.html - if altitude <= feet(36152): - temperature_f = 59 - 0.00356 * altitude.feet - else: - # There's another formula for altitudes over 82k feet, but we better - # not be planning waypoints that high... - temperature_f = -70 - - temperature_k = (temperature_f + 459.67) * (5 / 9) - - # https://www.engineeringtoolbox.com/specific-heat-ratio-d_602.html - # Dependent on temperature, but varies very little (+/-0.001) - # between -40F and 180F. - heat_capacity_ratio = 1.4 - - # https://www.grc.nasa.gov/WWW/K-12/airplane/sound.html - gas_constant = 286 # m^2/s^2/K - c_sound = math.sqrt(heat_capacity_ratio * gas_constant * temperature_k) - return mps(c_sound) * value - - def __add__(self, other: Speed) -> Speed: - return kph(self.kph + other.kph) - - def __sub__(self, other: Speed) -> Speed: - return kph(self.kph - other.kph) - - def __mul__(self, other: Union[float, int]) -> Speed: - return kph(self.kph * other) - - __rmul__ = __mul__ - - def __truediv__(self, other: Union[float, int]) -> Speed: - return kph(self.kph / other) - - def __floordiv__(self, other: Union[float, int]) -> Speed: - return kph(self.kph // other) - - def __bool__(self) -> bool: - return not math.isclose(self.kph, 0.0) - - -def knots(value: float) -> Speed: - return Speed.from_knots(value) - - -def kph(value: float) -> Speed: - return Speed.from_kph(value) - - -def mps(value: float) -> Speed: - return Speed.from_meters_per_second(value) - - -def mach(value: float, altitude: Distance) -> Speed: - return Speed.from_mach(value, altitude) - - -SPEED_OF_SOUND_AT_SEA_LEVEL = knots(661.5) - - -@dataclass(frozen=True, order=True) -class Heading: - heading_in_degrees: int - - @property - def degrees(self) -> int: - return Heading.reduce_angle(self.heading_in_degrees) - - @property - def radians(self) -> float: - return math.radians(Heading.reduce_angle(self.heading_in_degrees)) - - @property - def opposite(self) -> Heading: - return self + Heading.from_degrees(180) - - @property - def right(self) -> Heading: - return self + Heading.from_degrees(90) - - @property - def left(self) -> Heading: - return self - Heading.from_degrees(90) - - def angle_between(self, other: Heading) -> Heading: - angle_between = abs(self.degrees - other.degrees) - if angle_between > 180: - angle_between = 360 - angle_between - return Heading.from_degrees(angle_between) - - @staticmethod - def reduce_angle(angle: int) -> int: - return angle % 360 - - @classmethod - def from_degrees(cls, angle: Union[int, float]) -> Heading: - return cls(Heading.reduce_angle(round(angle))) - - @classmethod - def from_radians(cls, angle: Union[int, float]) -> Heading: - deg = round(math.degrees(angle)) - return cls(Heading.reduce_angle(deg)) - - @classmethod - def random(cls, min_angle: int = 0, max_angle: int = 359) -> Heading: - return Heading.from_degrees(random.randint(min_angle, max_angle)) - - def __add__(self, other: Heading) -> Heading: - return Heading.from_degrees(self.degrees + other.degrees) - - def __sub__(self, other: Heading) -> Heading: - return Heading.from_degrees(self.degrees - other.degrees) - - def __str__(self) -> str: - return f"{self.heading_in_degrees}°" - - -@dataclass(frozen=True, order=True) -class Pressure: - pressure_in_inches_hg: float - - @property - def inches_hg(self) -> float: - return self.pressure_in_inches_hg - - @property - def mm_hg(self) -> float: - return self.pressure_in_inches_hg * INHG_TO_MMHG - - @property - def hecto_pascals(self) -> float: - return self.pressure_in_inches_hg * INHG_TO_HPA - - -def inches_hg(value: float) -> Pressure: - return Pressure(value) - - -@dataclass(frozen=True, order=True) -class Mass: - mass_in_kg: float - - @property - def pounds(self) -> float: - return self.mass_in_kg * KG_TO_LBS - - @property - def kgs(self) -> float: - return self.mass_in_kg - - -def pounds(value: float) -> Mass: - return Mass(value * LBS_TO_KG) - - -def kgs(value: float) -> Mass: - return Mass(value) - - -PairwiseT = TypeVar("PairwiseT") - - -def pairwise(iterable: Iterable[PairwiseT]) -> Iterable[tuple[PairwiseT, PairwiseT]]: - """ - itertools recipe - s -> (s0,s1), (s1,s2), (s2, s3), ... - """ - a, b = itertools.tee(iterable) - next(b, None) - return zip(a, b) - - -def interpolate(value1: float, value2: float, factor: float, clamp: bool) -> float: - """Inerpolate between two values, factor 0-1""" - interpolated = value1 + (value2 - value1) * factor - - if clamp: - bigger_value = max(value1, value2) - smaller_value = min(value1, value2) - return min(bigger_value, max(smaller_value, interpolated)) - else: - return interpolated - - -def dcs_to_shapely_point(point: Point) -> ShapelyPoint: - return ShapelyPoint(point.x, point.y) - - -def escape_string_for_lua(value: str) -> str: - """Escapes special characters from a string. - This prevents scripting errors in lua scripts""" - value = value.replace('"', "'") # Replace Double Quote as this is the delimiter - value = value.replace(os.sep, "/") # Replace Backslash as path separator - return "{0}".format(value) diff --git a/game/version.py b/game/version.py deleted file mode 100644 index bcc31decc..000000000 --- a/game/version.py +++ /dev/null @@ -1,194 +0,0 @@ -from pathlib import Path - - -MAJOR_VERSION = 11 -MINOR_VERSION = 0 -MICRO_VERSION = 0 -VERSION_NUMBER = ".".join(str(v) for v in (MAJOR_VERSION, MINOR_VERSION, MICRO_VERSION)) - - -def _optional_build_id_component(path: Path) -> str | None: - if path.exists(): - return path.read_text().strip() - return None - - -BUILD_NUMBER = _optional_build_id_component(Path("resources/buildnumber")) -GIT_SHA = _optional_build_id_component(Path("resources/gitsha")) - - -def _build_version_string() -> str: - components = [VERSION_NUMBER] - if BUILD_NUMBER is not None: - components.append(BUILD_NUMBER) - if GIT_SHA is not None: - components.append(GIT_SHA) - if not Path("resources/final").exists(): - components.append("preview") - - return "-".join(components) - - -#: Current version of Liberation. -VERSION = _build_version_string() - -#: The latest version of the campaign format. Increment this version whenever all -#: existing campaigns should be flagged as incompatible in the UI. We will still attempt -#: to load old campaigns, but this provides a warning to the user that the campaign may -#: not work correctly. -#: -#: There is no verification that the campaign author updated their campaign correctly -#: this is just a UI hint. -#: -#: Version history: -#: -#: Version 0 -#: * Unknown compatibility. -#: -#: Version 1 -#: * Compatible with Liberation 2.5. -#: -#: Version 2 -#: * Front line endpoints now define convoy origin/destination waypoints. They should be -#: placed on or near roads. -#: * Factories (Workshop_A) define factory objectives. Only control points with -#: factories will be able to recruit ground units, so they should exist in sufficient -#: number and be protected by IADS. -#: -#: Version 3 -#: * Bulker Handy Winds define shipping lanes. They should be placed in port areas that -#: are navigable by ships and have a route to another port area. DCS ships *will not* -#: avoid driving into islands, so ensure that their waypoints plot a navigable route. -#: -#: Version 4 -#: * TriggerZones define map based building targets. White TriggerZones created by right -#: clicking an object and using "assign as..." define the buildings within an objective. -#: Blue circular TriggerZones created normally must surround groups of one or more -#: white TriggerZones to define an objective. If a white TriggerZone is not surrounded -#: by a blue circular TriggerZone, campaign creation will fail. Blue circular -#: TriggerZones must also have their first property's value field define the type of -#: objective (a valid value for a building TGO category, from `game.db.PRICES`). -#: -#: Version 4.1 -#: * All objective types may now be set as required generation (similar to the required -#: IADS generation). This includes: -#: * SHORADS -#: * Armor groups -#: * Strike targets -#: * Offshore strike targets -#: * Ships -#: * Missile sites -#: * Coastal defenses -#: -#: See the unit lists in MizCampaignLoader in conflicttheater.py for unit types. -#: -#: Version 4.2 -#: * Adds support for AAA objectives. Place with any of the following units (either red -#: or blue): -#: * Flak18, -#: * Vulcan, -#: * ZSU_23_4_Shilka, -#: -#: Version 5.0 -#: * Ammunition Depots objective locations are now predetermined using the "Ammunition -# Depot" Warehouse object, and through trigger zone based scenery objects. -#: * The number of alive Ammunition Depot objective buildings connected to a control -#: point directly influences how many ground units can be supported on the front -#: line. -#: * The number of supported ground units at any control point is artificially -#: capped at 50, even if the number of alive Ammunition Depot objectives can -#: support more. -#: -#: Version 6.0 -#: * Random objective generation no is longer supported. Fixed objective locations were -#: added in 4.1. -#: -#: Version 6.1 -#: * Support for new Syrian airfields in DCS 2.7.2.7910.1 (Cyprus update). -#: -#: Version 7.0 -#: * DCS 2.7.2.7910.1 (Cyprus update) changed the IDs of scenery strike targets. Any -#: mission using map buildings as strike targets must check and potentially recreate -#: all those objectives. This definitely affects all Syria campaigns, other maps are -#: not yet verified. -#: -#: Version 7.1 -#: * Support for Mariana Islands terrain -#: -#: Version 8.0 -#: * DCS 2.7.4.9632 changed scenery target IDs. Any mission using map buildings as -#: strike targets must check and potentially recreate all those objectives. -#: -#: Version 8.1 -#: * You can now add "Invisible FARP" static to FOB to add helicopter slots -#: -#: Version 9.0 -#: * Campaign files now define the initial squadron layouts. See -#: https://github.com/dcs-liberation/dcs_liberation/wiki/Custom-Campaigns. -#: * CV and LHA control points now get their names from the group name in the campaign -#: miz. -#: -#: Version 9.1 -#: * Campaign files can optionally define a start date with -#: `recommended_start_date: YYYY-MM-DD`. -#: -#: Version 9.2 -#: * Squadrons defined in campaign files can optionally setup squadrons' name, -#: nickname and/or generated female pilot name percentage -#: -#: Version 10.0 -#: * The new introduced layout system extends the mission generation so that a -#: campaign designer can now define the heading of the ground objects which will be -#: also used later in mission generation to orient the group accordingly. -#: This removes the randomization of the orientation from the generation. -#: Most campaigns will not need any updates and will work out of the box. -#: If the campaign designer sets the heading to 0 then we will automatically change -#: the orientation of the generated TGO to head towards the conflict if it is -#: required by the TGO to work properly. Values other than 0 will prevent the -#: automatic orientation. -#: -#: Version 10.1 -#: * Campaign designers can now define the recommended economy settings: -#: `recommended_player_money: 2000`. -#: `recommended_enemy_money: 2000`. -#: `recommended_player_income_multiplier: 1.0`. -#: `recommended_enemy_income_multiplier: 1.0`. -#: -#: Version 10.2 -#: * Campaign files can optionally define the iads configuration -#: It is possible to define if the campaign supports advanced iads -#: -#: Version 10.3 -#: * Campaign files can optionally include a start time in their recommended_start_date -#: field. For example, `recommended_start_date: 2022-08-31 13:30:00` will have the -#: first turn start at 13:30. If omitted, or if only a date is given, the mission will -#: start at a random hour in the middle of the day as before. -#: -#: Version 10.4 -#: * Support for the Falklands. -#: -#: Version 10.5 -#: * Support for scenery objectives defined by quad zones. -#: -#: Version 10.6 -#: * Support in-line definitions of campaign-specific factions. -#: -#: Version 10.7 -#: * Support for defining squadron sizes. -#: -#: Version 10.8 -#: * Support for Normandy 2. -#: -#: Version 10.9 -#: * Campaign is compatible with new squadron rules. The default air wing configuration -#: has enough parking available at each base when squadrons begin at full strength. -#: -#: Version 10.10 -#: * Support for Sinai. -#: -#: Version 10.11 -#: * Support for ferry-only bases. -#: -#: Version 11.0 -#: * The squadron sizes introduced in 10.7 are required. -CAMPAIGN_FORMAT_VERSION = (11, 0) diff --git a/game/weather/__init__.py b/game/weather/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/game/weather/atmosphericconditions.py b/game/weather/atmosphericconditions.py deleted file mode 100644 index d075ba067..000000000 --- a/game/weather/atmosphericconditions.py +++ /dev/null @@ -1,17 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.utils import Pressure - - -@dataclass(frozen=True) -class AtmosphericConditions: - #: Pressure at sea level. - qnh: Pressure - - #: Temperature at sea level in Celcius. - temperature_celsius: float - - #: Turbulence per 10 cm. - turbulence_per_10cm: float diff --git a/game/weather/clouds.py b/game/weather/clouds.py deleted file mode 100644 index ed1e087bf..000000000 --- a/game/weather/clouds.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import annotations - -import random -from dataclasses import dataclass, field -from typing import Optional - -from dcs.cloud_presets import Clouds as PydcsClouds -from dcs.weather import Weather as PydcsWeather, CloudPreset - - -@dataclass(frozen=True) -class Clouds: - base: int - density: int - thickness: int - precipitation: PydcsWeather.Preceptions - preset: Optional[CloudPreset] = field(default=None) - - @classmethod - def random_preset(cls, rain: bool) -> Clouds: - clouds = (p.value for p in PydcsClouds) - if rain: - presets = [p for p in clouds if "Rain" in p.name] - else: - presets = [p for p in clouds if "Rain" not in p.name] - preset = random.choice(presets) - return Clouds( - base=random.randint(preset.min_base, preset.max_base), - density=0, - thickness=0, - precipitation=PydcsWeather.Preceptions.None_, - preset=preset, - ) diff --git a/game/weather/conditions.py b/game/weather/conditions.py deleted file mode 100644 index 2737d60c7..000000000 --- a/game/weather/conditions.py +++ /dev/null @@ -1,95 +0,0 @@ -from __future__ import annotations - -import datetime -import logging -import random -from dataclasses import dataclass - -from game.settings import Settings -from game.theater import ConflictTheater, DaytimeMap, SeasonalConditions -from game.theater.seasonalconditions import determine_season -from game.timeofday import TimeOfDay -from game.weather.weather import Weather, Thunderstorm, Raining, Cloudy, ClearSkies - - -@dataclass -class Conditions: - time_of_day: TimeOfDay - start_time: datetime.datetime - weather: Weather - - @classmethod - def generate( - cls, - theater: ConflictTheater, - day: datetime.date, - time_of_day: TimeOfDay, - settings: Settings, - forced_time: datetime.time | None = None, - ) -> Conditions: - # The time might be forced by the campaign for the first turn. - if forced_time is not None: - _start_time = datetime.datetime.combine(day, forced_time) - else: - _start_time = cls.generate_start_time( - theater, day, time_of_day, settings.night_disabled - ) - - return cls( - time_of_day=time_of_day, - start_time=_start_time, - weather=cls.generate_weather(theater.seasonal_conditions, day, time_of_day), - ) - - @classmethod - def generate_start_time( - cls, - theater: ConflictTheater, - day: datetime.date, - time_of_day: TimeOfDay, - night_disabled: bool, - ) -> datetime.datetime: - if night_disabled: - logging.info("Skip Night mission due to user settings") - time_range = DaytimeMap( - dawn=(datetime.time(hour=8), datetime.time(hour=9)), - day=(datetime.time(hour=10), datetime.time(hour=12)), - dusk=(datetime.time(hour=12), datetime.time(hour=14)), - night=(datetime.time(hour=14), datetime.time(hour=17)), - ).range_of(time_of_day) - else: - time_range = theater.daytime_map.range_of(time_of_day) - - # Starting missions on the hour is a nice gameplay property, so keep the random - # time constrained to that. DaytimeMap enforces that we have only whole hour - # ranges for now, so we don't need to worry about accidentally changing the time - # of day by truncating sub-hours. - time = datetime.time( - hour=random.randint(time_range[0].hour, time_range[1].hour) - ) - return datetime.datetime.combine(day, time) - - @classmethod - def generate_weather( - cls, - seasonal_conditions: SeasonalConditions, - day: datetime.date, - time_of_day: TimeOfDay, - ) -> Weather: - season = determine_season(day) - logging.debug("Weather: Season {}".format(season)) - weather_chances = seasonal_conditions.weather_type_chances[season] - chances: dict[ - type[ClearSkies] | type[Cloudy] | type[Raining] | type[Thunderstorm], float - ] = { - Thunderstorm: weather_chances.thunderstorm, - Raining: weather_chances.raining, - Cloudy: weather_chances.cloudy, - ClearSkies: weather_chances.clear_skies, - } - logging.debug("Weather: Chances {}".format(weather_chances)) - weather_type = random.choices( - list(chances.keys()), weights=list(chances.values()) - )[0] - logging.debug("Weather: Type {}".format(weather_type)) - return weather_type(seasonal_conditions, day, time_of_day) diff --git a/game/weather/fog.py b/game/weather/fog.py deleted file mode 100644 index f998429d0..000000000 --- a/game/weather/fog.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from game.utils import Distance - - -@dataclass(frozen=True) -class Fog: - visibility: Distance - thickness: int diff --git a/game/weather/weather.py b/game/weather/weather.py deleted file mode 100644 index 0573766d1..000000000 --- a/game/weather/weather.py +++ /dev/null @@ -1,305 +0,0 @@ -from __future__ import annotations - -import datetime -import logging -import math -import random -from abc import ABC, abstractmethod -from typing import Optional, TYPE_CHECKING - -from dcs.weather import Weather as PydcsWeather - -from game.timeofday import TimeOfDay -from game.utils import ( - Pressure, - inches_hg, - interpolate, - meters, -) -from game.weather.atmosphericconditions import AtmosphericConditions -from game.weather.clouds import Clouds -from game.weather.fog import Fog -from game.weather.weatherarchetype import WeatherArchetype, WeatherArchetypes -from game.weather.wind import WindConditions - -if TYPE_CHECKING: - from game.theater.seasonalconditions import SeasonalConditions - - -class Weather(ABC): - def __init__( - self, - seasonal_conditions: SeasonalConditions, - day: datetime.date, - time_of_day: TimeOfDay, - ) -> None: - # Future improvement: Use theater, day and time of day - # to get a more realistic conditions - self.atmospheric = self.generate_atmospheric( - seasonal_conditions, day, time_of_day - ) - self.clouds = self.generate_clouds() - self.fog = self.generate_fog() - self.wind = self.generate_wind() - - def generate_atmospheric( - self, - seasonal_conditions: SeasonalConditions, - day: datetime.date, - time_of_day: TimeOfDay, - ) -> AtmosphericConditions: - pressure = self.interpolate_summer_winter( - seasonal_conditions.summer_avg_pressure, - seasonal_conditions.winter_avg_pressure, - day, - ) - temperature = self.interpolate_summer_winter( - seasonal_conditions.summer_avg_temperature, - seasonal_conditions.winter_avg_temperature, - day, - ) - - seasonal_turbulence = self.interpolate_seasonal_turbulence( - seasonal_conditions.high_avg_yearly_turbulence_per_10cm, - seasonal_conditions.low_avg_yearly_turbulence_per_10cm, - day, - ) - - day_turbulence = seasonal_conditions.solar_noon_turbulence_per_10cm - night_turbulence = seasonal_conditions.midnight_turbulence_per_10cm - time_of_day_turbulence = self.interpolate_solar_activity( - time_of_day, day_turbulence, night_turbulence - ) - - random_turbulence = random.normalvariate(mu=0, sigma=0.5) - - turbulence = abs( - seasonal_turbulence + time_of_day_turbulence + random_turbulence - ) - - if time_of_day == TimeOfDay.Day: - temperature += seasonal_conditions.temperature_day_night_difference / 2 - if time_of_day == TimeOfDay.Night: - temperature -= seasonal_conditions.temperature_day_night_difference / 2 - pressure += self.pressure_adjustment - temperature += self.temperature_adjustment - turbulence += self.turbulence_adjustment - logging.debug( - "Weather: Before random: temp {} press {}".format(temperature, pressure) - ) - conditions = AtmosphericConditions( - qnh=self.random_pressure(pressure), - temperature_celsius=self.random_temperature(temperature), - turbulence_per_10cm=turbulence, - ) - logging.debug( - "Weather: After random: temp {} press {}".format( - conditions.temperature_celsius, conditions.qnh.pressure_in_inches_hg - ) - ) - return conditions - - @property - @abstractmethod - def archetype(self) -> WeatherArchetype: - ... - - @property - def pressure_adjustment(self) -> float: - raise NotImplementedError - - @property - def temperature_adjustment(self) -> float: - raise NotImplementedError - - @property - def turbulence_adjustment(self) -> float: - raise NotImplementedError - - def generate_clouds(self) -> Optional[Clouds]: - raise NotImplementedError - - def generate_fog(self) -> Optional[Fog]: - if random.randrange(5) != 0: - return None - return Fog( - visibility=meters(random.randint(2500, 5000)), - thickness=random.randint(100, 500), - ) - - def generate_wind(self) -> WindConditions: - return self.archetype.wind_parameters.speed.random_wind() - - @staticmethod - def random_cloud_base() -> int: - return random.randint(2000, 3000) - - @staticmethod - def random_cloud_thickness() -> int: - return random.randint(100, 400) - - @staticmethod - def random_pressure(average_pressure: float) -> Pressure: - # "Safe" constants based roughly on ME and viper altimeter. - # Units are inches of mercury. - SAFE_MIN = 28.4 - SAFE_MAX = 30.9 - # Use normalvariate to get normal distribution, more realistic than uniform - pressure = random.normalvariate(average_pressure, 0.1) - return inches_hg(max(SAFE_MIN, min(SAFE_MAX, pressure))) - - @staticmethod - def random_temperature(average_temperature: float) -> float: - # "Safe" constants based roughly on ME. - # Temperatures are in Celcius. - SAFE_MIN = -12 - SAFE_MAX = 49 - # Use normalvariate to get normal distribution, more realistic than uniform - temperature = random.normalvariate(average_temperature, 2) - temperature = round(temperature) - return max(SAFE_MIN, min(SAFE_MAX, temperature)) - - @staticmethod - def interpolate_summer_winter( - summer_value: float, winter_value: float, day: datetime.date - ) -> float: - day_of_year = day.timetuple().tm_yday - day_of_year_peak_summer = 183 - distance_from_peak_summer = abs(-day_of_year_peak_summer + day_of_year) - winter_factor = distance_from_peak_summer / day_of_year_peak_summer - return interpolate(summer_value, winter_value, winter_factor, clamp=True) - - @staticmethod - def interpolate_seasonal_turbulence( - high_value: float, low_value: float, day: datetime.date - ) -> float: - day_of_year = day.timetuple().tm_yday - day_of_year_peak_summer = 183 - distance_from_peak_summer = -day_of_year_peak_summer + day_of_year - - amplitude = 0.5 * (high_value - low_value) - offset = amplitude + low_value - - # A high peak in summer and winter, between high_value and low_value. - return ( - amplitude * math.cos(4 * math.pi * distance_from_peak_summer / 365.25) - + offset - ) - - @staticmethod - def interpolate_solar_activity( - time_of_day: TimeOfDay, high: float, low: float - ) -> float: - scale: float = 0 - - match time_of_day: - case TimeOfDay.Dawn: - scale = 0.4 - case TimeOfDay.Day: - scale = 1 - case TimeOfDay.Dusk: - scale = 0.6 - case TimeOfDay.Night: - scale = 0 - - return interpolate(value1=low, value2=high, factor=scale, clamp=True) - - -class ClearSkies(Weather): - @property - def archetype(self) -> WeatherArchetype: - return WeatherArchetypes.with_id("clear") - - @property - def pressure_adjustment(self) -> float: - return 0.22 - - @property - def temperature_adjustment(self) -> float: - return 3.0 - - @property - def turbulence_adjustment(self) -> float: - return 0.0 - - def generate_clouds(self) -> Optional[Clouds]: - return None - - def generate_fog(self) -> Optional[Fog]: - return None - - -class Cloudy(Weather): - @property - def archetype(self) -> WeatherArchetype: - return WeatherArchetypes.with_id("cloudy") - - @property - def pressure_adjustment(self) -> float: - return 0.0 - - @property - def temperature_adjustment(self) -> float: - return 0.0 - - @property - def turbulence_adjustment(self) -> float: - return 0.75 - - def generate_clouds(self) -> Optional[Clouds]: - return Clouds.random_preset(rain=False) - - def generate_fog(self) -> Optional[Fog]: - # DCS 2.7 says to not use fog with the cloud presets. - return None - - -class Raining(Weather): - @property - def archetype(self) -> WeatherArchetype: - return WeatherArchetypes.with_id("raining") - - @property - def pressure_adjustment(self) -> float: - return -0.22 - - @property - def temperature_adjustment(self) -> float: - return -3.0 - - @property - def turbulence_adjustment(self) -> float: - return 1.5 - - def generate_clouds(self) -> Optional[Clouds]: - return Clouds.random_preset(rain=True) - - def generate_fog(self) -> Optional[Fog]: - # DCS 2.7 says to not use fog with the cloud presets. - return None - - -class Thunderstorm(Weather): - @property - def archetype(self) -> WeatherArchetype: - return WeatherArchetypes.with_id("thunderstorm") - - @property - def pressure_adjustment(self) -> float: - return 0.1 - - @property - def temperature_adjustment(self) -> float: - return -3.0 - - @property - def turbulence_adjustment(self) -> float: - return 3.0 - - def generate_clouds(self) -> Optional[Clouds]: - return Clouds( - base=self.random_cloud_base(), - density=random.randint(9, 10), - thickness=self.random_cloud_thickness(), - precipitation=PydcsWeather.Preceptions.Thunderstorm, - ) diff --git a/game/weather/weatherarchetype.py b/game/weather/weatherarchetype.py deleted file mode 100644 index ebc36953e..000000000 --- a/game/weather/weatherarchetype.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from pathlib import Path -from typing import Any - -import yaml - -from .windspeedgenerators import WindSpeedGenerator - - -@dataclass(frozen=True) -class WindParameters: - speed: WindSpeedGenerator - - @staticmethod - def from_data(data: dict[str, Any]) -> WindParameters: - return WindParameters(speed=WindSpeedGenerator.from_data(data["speed"])) - - -@dataclass(frozen=True) -class WeatherArchetype: - id: str - wind_parameters: WindParameters - - @staticmethod - def from_data(data: dict[str, Any]) -> WeatherArchetype: - return WeatherArchetype( - id=data["id"], wind_parameters=WindParameters.from_data(data["wind"]) - ) - - @staticmethod - def from_yaml(path: Path) -> WeatherArchetype: - with path.open(encoding="utf-8") as yaml_file: - data = yaml.safe_load(yaml_file) - return WeatherArchetype.from_data(data) - - -class WeatherArchetypes: - _by_id: dict[str, WeatherArchetype] | None = None - - @classmethod - def with_id(cls, ident: str) -> WeatherArchetype: - if cls._by_id is None: - cls._by_id = cls.load() - return cls._by_id[ident] - - @staticmethod - def load() -> dict[str, WeatherArchetype]: - by_id = {} - for path in Path("resources/weather/archetypes").glob("*.yaml"): - archetype = WeatherArchetype.from_yaml(path) - if archetype.id in by_id: - raise RuntimeError( - f"Found duplicate weather archetype ID: {archetype.id}" - ) - by_id[archetype.id] = archetype - return by_id diff --git a/game/weather/wind.py b/game/weather/wind.py deleted file mode 100644 index dd762b26c..000000000 --- a/game/weather/wind.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass - -from dcs.weather import Wind - - -@dataclass(frozen=True) -class WindConditions: - at_0m: Wind - at_2000m: Wind - at_8000m: Wind diff --git a/game/weather/windspeedgenerators.py b/game/weather/windspeedgenerators.py deleted file mode 100644 index 2afce3d68..000000000 --- a/game/weather/windspeedgenerators.py +++ /dev/null @@ -1,95 +0,0 @@ -from __future__ import annotations - -import random -from abc import ABC, abstractmethod -from dataclasses import dataclass -from typing import Any - -from dcs.weather import Wind - -from game.utils import Speed, knots, Heading -from .wind import WindConditions - - -@dataclass(frozen=True) -class WeibullWindSpeedParameters: - shape: float - scale: Speed - - @staticmethod - def from_data(data: dict[str, Any]) -> WeibullWindSpeedParameters: - return WeibullWindSpeedParameters( - shape=data["shape"], scale=knots(data["scale_kts"]) - ) - - -class WindSpeedGenerator(ABC): - @abstractmethod - def random_wind(self) -> WindConditions: - ... - - @staticmethod - def from_data(data: dict[str, Any]) -> WindSpeedGenerator: - if len(data) != 1: - raise ValueError( - f"Wind speed dict has wrong number of keys ({len(data)}). Expected 1." - ) - name = list(data.keys())[0] - match name: - case "weibull": - return WeibullWindSpeedGenerator.from_data(data["weibull"]) - raise KeyError(f"Unknown wind speed generator type: {name}") - - -class WeibullWindSpeedGenerator(WindSpeedGenerator): - def __init__( - self, - at_msl: WeibullWindSpeedParameters, - at_2000m: WeibullWindSpeedParameters, - at_8000m: WeibullWindSpeedParameters, - ) -> None: - self.at_msl = at_msl - self.at_2000m = at_2000m - self.at_8000m = at_8000m - - def random_wind(self) -> WindConditions: - wind_direction = Heading.random() - wind_direction_2000m = wind_direction + Heading.random(-90, 90) - wind_direction_8000m = wind_direction + Heading.random(-90, 90) - - # The first parameter is the scale. 63.2% of all results will fall below that - # value. - # https://www.itl.nist.gov/div898/handbook/eda/section3/weibplot.htm - msl = random.weibullvariate( - self.at_msl.scale.meters_per_second, self.at_msl.shape - ) - at_2000m = random.weibullvariate( - msl + self.at_2000m.scale.meters_per_second, self.at_2000m.shape - ) - at_8000m = random.weibullvariate( - at_2000m + self.at_8000m.scale.meters_per_second, self.at_8000m.shape - ) - - # DCS is limited to 97 knots wind speed. - max_supported_wind_speed = knots(97).meters_per_second - - return WindConditions( - # Always some wind to make the smoke move a bit. - at_0m=Wind(wind_direction.degrees, max(1.0, msl)), - at_2000m=Wind( - wind_direction_2000m.degrees, - min(max_supported_wind_speed, at_2000m), - ), - at_8000m=Wind( - wind_direction_8000m.degrees, - min(max_supported_wind_speed, at_8000m), - ), - ) - - @staticmethod - def from_data(data: dict[str, Any]) -> WindSpeedGenerator: - return WeibullWindSpeedGenerator( - at_msl=WeibullWindSpeedParameters.from_data(data["at_msl"]), - at_2000m=WeibullWindSpeedParameters.from_data(data["at_2000m"]), - at_8000m=WeibullWindSpeedParameters.from_data(data["at_8000m"]), - ) diff --git a/game/zipfileext.py b/game/zipfileext.py deleted file mode 100644 index 05326c4ee..000000000 --- a/game/zipfileext.py +++ /dev/null @@ -1,34 +0,0 @@ -import shutil -from pathlib import Path -from tempfile import TemporaryDirectory -from zipfile import ZipFile - - -class ZipFileExt: - @staticmethod - def remove_member(path: Path, name: str, missing_ok: bool = False) -> None: - """Replaces the archive with a copy that excludes one member. - - This is needed to workaround Python's lack of a ZipFile.remove() or a way to - overwrite existing members. Attempting to update a member in a zipfile will - write a duplicate entry: https://github.com/python/cpython/issues/51067. - """ - with ZipFile(path, "r") as zip_file: - if name not in zip_file.namelist(): - if missing_ok: - return - raise ValueError(f"Cannot override {name} as it does not exist") - - # Doing this by extracting all the files to a temporary directory is faster than - # reading and writing a file at a time (1-5 seconds vs 0.5 seconds for a save - # bundle). - with TemporaryDirectory() as temp_dir_str: - temp_dir = Path(temp_dir_str) - shutil.unpack_archive(path, temp_dir) - (temp_dir / name).unlink() - shutil.make_archive( - # shutil.make_archive automatically adds the extension - str(path.with_suffix("")), - "zip", - root_dir=temp_dir_str, - ) diff --git a/installer/ISCC.exe b/installer/ISCC.exe deleted file mode 100644 index 72a8c55b8..000000000 Binary files a/installer/ISCC.exe and /dev/null differ diff --git a/installer/dcs_liberation.iss b/installer/dcs_liberation.iss deleted file mode 100644 index c20edb057..000000000 --- a/installer/dcs_liberation.iss +++ /dev/null @@ -1,51 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "DCS Liberation" -#define MyAppVersion "{{version}}" -#define MyAppPublisher "Khopa" -#define MyAppURL "https://github.com/dcs-liberation/dcs_liberation/wiki" -#define MyAppExeName "liberation_main.exe" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{6753B352-D281-42CB-9AFA-5E93EB90AA5A} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={autopf}\{#MyAppName} -DefaultGroupName={#MyAppName} -AllowNoIcons=yes -; Remove the following line to run in administrative install mode (install for all users.) -PrivilegesRequired=lowest -PrivilegesRequiredOverridesAllowed=dialog -OutputDir=..\dist -OutputBaseFilename=dcs_liberation -SetupIconFile=..\resources\icon.ico -UninstallDisplayIcon={app}\liberation_main.exe -Compression=lzma -SolidCompression=yes -WizardStyle=modern - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked - -[Files] -Source: "..\dist\dcs_liberation\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -[Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon - -[Run] -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - diff --git a/liberation_theme.json b/liberation_theme.json deleted file mode 100644 index 7fa657abd..000000000 --- a/liberation_theme.json +++ /dev/null @@ -1 +0,0 @@ -{"theme_index": 1} \ No newline at end of file diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index fe6d3348d..000000000 --- a/mypy.ini +++ /dev/null @@ -1,28 +0,0 @@ -[mypy] -# TODO: Cleanup so we can enable the checks commented out here. -check_untyped_defs = True -# disallow_any_decorated = True -# disallow_any_expr = True -disallow_any_generics = True -# disallow_any_unimported = True -disallow_untyped_decorators = True -disallow_untyped_defs = True -follow_imports = silent -# implicit_reexport = False -namespace_packages = True -no_implicit_optional = True -warn_redundant_casts = True -# warn_return_any = True -warn_unreachable = True -warn_unused_ignores = True -plugins = pydantic.mypy - -[mypy-faker.*] -ignore_missing_imports = True - -[mypy-shapely.*] -# https://github.com/Toblerity/Shapely/issues/721 -ignore_missing_imports = True - -[mypy-uvicorn.*] -ignore_missing_imports = True \ No newline at end of file diff --git a/pydcs_extensions/__init__.py b/pydcs_extensions/__init__.py deleted file mode 100644 index daceb4b46..000000000 --- a/pydcs_extensions/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from .a4ec import * -from .f104 import * -from .f22a import * -from .f4 import * -from .frenchpack import * -from .hercules import * -from .highdigitsams import * -from .jas39 import * -from .ov10a import * -from .su57 import * -from .uh60l import * -from .fa18efg import * - - -def load_mods() -> None: - """Loads all mods. - - Note that this function doesn't *do* anything. Its purpose is to prevent editors - from removing `import pydcs_extensions` when it is "unused", because mod imports - have side effects (unit types are registered with pydcs). - """ diff --git a/pydcs_extensions/a4ec/__init__.py b/pydcs_extensions/a4ec/__init__.py deleted file mode 100644 index 8cdbd5e41..000000000 --- a/pydcs_extensions/a4ec/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .a4ec import * diff --git a/pydcs_extensions/a4ec/a4ec.py b/pydcs_extensions/a4ec/a4ec.py deleted file mode 100644 index 8f88b6f9b..000000000 --- a/pydcs_extensions/a4ec/a4ec.py +++ /dev/null @@ -1,2099 +0,0 @@ -from typing import Any, Dict, Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsA4EC: - AN_M66A2___2000lb_GP_Bomb_LD = { - "clsid": "{AN-M66A2}", - "name": "AN-M66A2 - 2000lb GP Bomb LD", - "weight": 970.68688, - } - AN_M81___260lb_GP_Bomb_LD = { - "clsid": "{AN-M81}", - "name": "AN-M81 - 260lb GP Bomb LD", - "weight": 117.93392, - } - AN_M88___220lb_GP_Bomb_LD = { - "clsid": "{AN-M88}", - "name": "AN-M88 - 220lb GP Bomb LD", - "weight": 98.0665904, - } - Bomblets_BLU_3B_x_19__HE = { - "clsid": "{BLU_3B_GROUP}", - "name": "Bomblets BLU-3B x 19, HE", - "weight": 0.793786, - } - Bomblets_BLU_4B_x_27__HE = { - "clsid": "{BLU_4B_GROUP}", - "name": "Bomblets BLU-4B x 27, HE", - "weight": 0.5443104, - } - CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE = { - "clsid": "{CBU-1/A}", - "name": "CBU-1/A pod - 19 x tubes of Bomblets BLU-4B x 27, HE", - "weight": 337.2910112, - } - CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE_ = { - "clsid": "{CBU-1/A*2}", - "name": "CBU-1/A pod - 19 x tubes of Bomblets BLU-4B x 27, HE", - "weight": 616.5222464, - } - CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = { - "clsid": "{CBU-2B/A}", - "name": "CBU-2B/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE", - "weight": 344.616522, - } - CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE_ = { - "clsid": "{CBU-2B/A*2}", - "name": "CBU-2B/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE", - "weight": 631.173268, - } - CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = { - "clsid": "{CBU-2/A}", - "name": "CBU-2/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE", - "weight": 344.616522, - } - CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE_ = { - "clsid": "{CBU-2/A*2}", - "name": "CBU-2/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE", - "weight": 631.173268, - } - CBU_DUMMY_pod___0_x_tubes_of_Bomblets_BLU_4B_x_27__HE = { - "clsid": "{CBU_DUMMY}", - "name": "CBU_DUMMY pod - 0 x tubes of Bomblets BLU-4B x 27, HE", - "weight": 58.059776, - } - Fuel_Tank_150_gallons = { - "clsid": "{DFT-150gal}", - "name": "Fuel Tank 150 gallons", - "weight": 515.888512, - } - Fuel_Tank_150_gallons__EMPTY_ = { - "clsid": "{DFT-150gal_EMPTY}", - "name": "Fuel Tank 150 gallons (EMPTY)", - "weight": 515.888512, - } - Fuel_Tank_300_gallons = { - "clsid": "{DFT-300gal}", - "name": "Fuel Tank 300 gallons", - "weight": 991.407336, - } - Fuel_Tank_300_gallons_ = { - "clsid": "{DFT-300gal_LR}", - "name": "Fuel Tank 300 gallons", - "weight": 998.664808, - } - Fuel_Tank_300_gallons__EMPTY_ = { - "clsid": "{DFT-300gal_EMPTY}", - "name": "Fuel Tank 300 gallons (EMPTY)", - "weight": 991.407336, - } - Fuel_Tank_300_gallons__EMPTY__ = { - "clsid": "{DFT-300gal_LR_EMPTY}", - "name": "Fuel Tank 300 gallons (EMPTY)", - "weight": 998.664808, - } - Fuel_Tank_400_gallons = { - "clsid": "{DFT-400gal}", - "name": "Fuel Tank 400 gallons", - "weight": 1320.06208, - } - Fuel_Tank_400_gallons__EMPTY_ = { - "clsid": "{DFT-400gal_EMPTY}", - "name": "Fuel Tank 400 gallons (EMPTY)", - "weight": 1320.06208, - } - LAU_7_with_AIM_9J_Sidewinder_IR_AAM = { - "clsid": "{AIM-9J-ON-ADAPTER}", - "name": "LAU-7 with AIM-9J Sidewinder IR AAM", - "weight": 115.84, - } - LAU_7_with_AIM_9P3_Sidewinder_IR_AAM = { - "clsid": "{A4E-AIM-9P3-ON-ADAPTER}", - "name": "LAU-7 with AIM-9P3 Sidewinder IR AAM", - "weight": 121.7, - } - LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_ = { - "clsid": "{A4E-ASQ-T50-ON-ADAPTER}", - "name": "LAU-7 with AN/ASQ-T50 TCTS Pod - ACMI Pod", - "weight": 103.6, - } - Mk4_HIPEG___Gunpod = { - "clsid": "{Mk4 HIPEG}", - "name": "Mk4 HIPEG - Gunpod", - "weight": 612.35, - } - Mk_77_mod_0___750lb_Fire_Bomb_LD = { - "clsid": "{mk77mod0}", - "name": "Mk-77 mod 0 - 750lb Fire Bomb LD", - "weight": 340, - } - Mk_77_mod_1___500lb_Fire_Bomb_LD = { - "clsid": "{mk77mod1}", - "name": "Mk-77 mod 1 - 500lb Fire Bomb LD", - "weight": 230, - } - Mk_81_Snakeye___250lb_GP_Bomb_HD = { - "clsid": "{MK-81SE}", - "name": "Mk-81 Snakeye - 250lb GP Bomb HD", - "weight": 113.398, - } - _2_x_AN_M57___250lb_GP_Bomb_LD__TER_ = { - "clsid": "{AN-M57_TER_2_L}", - "name": "2 x AN-M57 - 250lb GP Bomb LD (TER)", - "weight": 273.6, - } - _2_x_AN_M57___250lb_GP_Bomb_LD__TER__ = { - "clsid": "{AN-M57_TER_2_R}", - "name": "2 x AN-M57 - 250lb GP Bomb LD (TER)", - "weight": 273.6, - } - _2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER_ = { - "clsid": "{CBU-1/A_TER_2_L}", - "name": "2 x CBU-1/A pod - 19 x tubes of Bomblets BLU-4B x 27, HE (TER)", - "weight": 722.1820224, - } - _2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER__ = { - "clsid": "{CBU-1/A_TER_2_R}", - "name": "2 x CBU-1/A pod - 19 x tubes of Bomblets BLU-4B x 27, HE (TER)", - "weight": 722.1820224, - } - _2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_ = { - "clsid": "{CBU-2B/A_TER_2_L}", - "name": "2 x CBU-2B/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE (TER)", - "weight": 827.324648, - } - _2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__ = { - "clsid": "{CBU-2B/A_TER_2_R}", - "name": "2 x CBU-2B/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE (TER)", - "weight": 827.324648, - } - _2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_ = { - "clsid": "{CBU-2/A_TER_2_L}", - "name": "2 x CBU-2/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE (TER)", - "weight": 736.833044, - } - _2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__ = { - "clsid": "{CBU-2/A_TER_2_R}", - "name": "2 x CBU-2/A pod - 19 x tubes of Bomblets BLU-3B x 19, HE (TER)", - "weight": 736.833044, - } - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_ = { - "clsid": "{LAU-10 ZUNI_TER_2_C}", - "name": "2 x LAU-10 pod - 4 x 127mm ZUNI, UnGd Rkts MK 71, HE/FRAG (TER)", - "weight": 596.392, - } - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER__ = { - "clsid": "{LAU-10 ZUNI_TER_2_L}", - "name": "2 x LAU-10 pod - 4 x 127mm ZUNI, UnGd Rkts MK 71, HE/FRAG (TER)", - "weight": 596.392, - } - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER___ = { - "clsid": "{LAU-10 ZUNI_TER_2_R}", - "name": "2 x LAU-10 pod - 4 x 127mm ZUNI, UnGd Rkts MK 71, HE/FRAG (TER)", - "weight": 596.392, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = { - "clsid": "{LAU-3 FFAR WP156_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 542.3414512, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__ = { - "clsid": "{LAU-3 FFAR WP156_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 542.3414512, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___ = { - "clsid": "{LAU-3 FFAR WP156_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 542.3414512, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = { - "clsid": "{LAU-3 FFAR Mk1 HE_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 487.184664, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__ = { - "clsid": "{LAU-3 FFAR Mk1 HE_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 487.184664, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___ = { - "clsid": "{LAU-3 FFAR Mk1 HE_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 487.184664, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_ = { - "clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 488.9083136, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER__ = { - "clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 488.9083136, - } - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER___ = { - "clsid": "{LAU-3 FFAR Mk5 HEAT_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 488.9083136, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = { - "clsid": "{LAU3_HE151_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 515.98, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__ = { - "clsid": "{LAU3_HE151_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 515.98, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___ = { - "clsid": "{LAU3_HE151_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 515.98, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = { - "clsid": "{LAU3_WP156_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 359.42, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__ = { - "clsid": "{LAU3_WP156_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 359.42, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___ = { - "clsid": "{LAU3_WP156_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 359.42, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU3_HE5_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 451.38, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__ = { - "clsid": "{LAU3_HE5_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 451.38, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___ = { - "clsid": "{LAU3_HE5_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 451.38, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = { - "clsid": "{LAU3_WP1B_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__ = { - "clsid": "{LAU3_WP1B_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___ = { - "clsid": "{LAU3_WP1B_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = { - "clsid": "{LAU3_WP61_TER_2_C}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__ = { - "clsid": "{LAU3_WP61_TER_2_L}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___ = { - "clsid": "{LAU3_WP61_TER_2_R}", - "name": '2 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 462.78, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 268.2262208, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER__ = { - "clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 268.2262208, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER___ = { - "clsid": "{LAU-68 FFAR Mk5 HEAT_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 268.2262208, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = { - "clsid": "{LAU-68 FFAR WP156_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 287.9121136, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__ = { - "clsid": "{LAU-68 FFAR WP156_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 287.9121136, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___ = { - "clsid": "{LAU-68 FFAR WP156_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 287.9121136, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = { - "clsid": "{LAU-68 FFAR Mk1 HE_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 267.591192, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__ = { - "clsid": "{LAU-68 FFAR Mk1 HE_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 267.591192, - } - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___ = { - "clsid": "{LAU-68 FFAR Mk1 HE_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 267.591192, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = { - "clsid": "{LAU-68 Hydra M151 HE_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__ = { - "clsid": "{LAU-68 Hydra M151 HE_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___ = { - "clsid": "{LAU-68 Hydra M151 HE_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = { - "clsid": "{LAU-68 Hydra WP156_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 276.52, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__ = { - "clsid": "{LAU-68 Hydra WP156_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 276.52, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___ = { - "clsid": "{LAU-68 Hydra WP156_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 276.52, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_ = { - "clsid": "{LAU-68 Hydra M257 PI_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M257, Para Illum (TER)', - "weight": 285.2, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER__ = { - "clsid": "{LAU-68 Hydra M257 PI_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M257, Para Illum (TER)', - "weight": 285.2, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER___ = { - "clsid": "{LAU-68 Hydra M257 PI_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M257, Para Illum (TER)', - "weight": 285.2, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_ = { - "clsid": "{LAU-68 Hydra M274 PS_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M274, Practice Smk (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER__ = { - "clsid": "{LAU-68 Hydra M274 PS_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M274, Practice Smk (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER___ = { - "clsid": "{LAU-68 Hydra M274 PS_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M274, Practice Smk (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_ = { - "clsid": "{LAU-68 Hydra Mk1 Practice_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk1, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER__ = { - "clsid": "{LAU-68 Hydra Mk1 Practice_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk1, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER___ = { - "clsid": "{LAU-68 Hydra Mk1 Practice_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk1, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU-68 Hydra Mk5 HEAT_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 251.74, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__ = { - "clsid": "{LAU-68 Hydra Mk5 HEAT_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 251.74, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___ = { - "clsid": "{LAU-68 Hydra Mk5 HEAT_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 251.74, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = { - "clsid": "{LAU-68 Hydra Mk61 Practice_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__ = { - "clsid": "{LAU-68 Hydra Mk61 Practice_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___ = { - "clsid": "{LAU-68 Hydra Mk61 Practice_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 255.94, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = { - "clsid": "{LAU-68 Hydra WTU1B Practice_TER_2_C}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__ = { - "clsid": "{LAU-68 Hydra WTU1B Practice_TER_2_L}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 274, - } - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___ = { - "clsid": "{LAU-68 Hydra WTU1B Practice_TER_2_R}", - "name": '2 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 274, - } - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_ = { - "clsid": "{Mk-20_TER_2_L}", - "name": "2 x Mk-20 Rockeye - 490lbs CBU, 247 x HEAT Bomblets (TER)", - "weight": 491.6, - } - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER__ = { - "clsid": "{Mk-20_TER_2_R}", - "name": "2 x Mk-20 Rockeye - 490lbs CBU, 247 x HEAT Bomblets (TER)", - "weight": 491.6, - } - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER___ = { - "clsid": "{Mk-20_TER_2_C}", - "name": "2 x Mk-20 Rockeye - 490lbs CBU, 247 x HEAT Bomblets (TER)", - "weight": 491.6, - } - _2_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__TER_ = { - "clsid": "{Mk-77 mod 1_TER_2_L}", - "name": "2 x Mk-77 mod 1 - 500lb Fire Bomb LD (TER)", - "weight": 507.6, - } - _2_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__TER__ = { - "clsid": "{Mk-77 mod 1_TER_2_R}", - "name": "2 x Mk-77 mod 1 - 500lb Fire Bomb LD (TER)", - "weight": 507.6, - } - _2_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__TER___ = { - "clsid": "{Mk-77 mod 1_TER_2_C}", - "name": "2 x Mk-77 mod 1 - 500lb Fire Bomb LD (TER)", - "weight": 507.6, - } - _2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_ = { - "clsid": "{Mk-82 Snakeye_TER_2_L}", - "name": "2 x Mk-82 Snakeye - 500lb GP Bomb HD (TER)", - "weight": 529.6, - } - _2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER__ = { - "clsid": "{Mk-82 Snakeye_TER_2_R}", - "name": "2 x Mk-82 Snakeye - 500lb GP Bomb HD (TER)", - "weight": 529.6, - } - _2_x_Mk_82___500lb_GP_Bomb_LD__TER_ = { - "clsid": "{Mk-82_TER_2_L}", - "name": "2 x Mk-82 - 500lb GP Bomb LD (TER)", - "weight": 529.6, - } - _2_x_Mk_82___500lb_GP_Bomb_LD__TER__ = { - "clsid": "{Mk-82_TER_2_R}", - "name": "2 x Mk-82 - 500lb GP Bomb LD (TER)", - "weight": 529.6, - } - _2_x_Mk_83___1000lb_GP_Bomb_LD__TER_ = { - "clsid": "{Mk-83_TER_2_C}", - "name": "2 x Mk-83 - 1000lb GP Bomb LD (TER)", - "weight": 941.6, - } - _3_x_AN_M57___250lb_GP_Bomb_LD__TER_ = { - "clsid": "{AN-M57_TER_3_C}", - "name": "3 x AN-M57 - 250lb GP Bomb LD (TER)", - "weight": 386.6, - } - _3_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_ = { - "clsid": "{LAU-10 ZUNI_TER_3_C}", - "name": "3 x LAU-10 pod - 4 x 127mm ZUNI, UnGd Rkts MK 71, HE/FRAG (TER)", - "weight": 870.788, - } - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = { - "clsid": "{LAU-3 FFAR WP156_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 789.7121768, - } - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = { - "clsid": "{LAU-3 FFAR Mk1 HE_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 706.976996, - } - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_ = { - "clsid": "{LAU-3 FFAR Mk5 HEAT_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 709.5624704, - } - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = { - "clsid": "{LAU3_HE151_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 750.17, - } - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = { - "clsid": "{LAU3_WP156_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 515.33, - } - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU3_HE5_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 653.27, - } - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = { - "clsid": "{LAU3_WP1B_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 670.37, - } - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = { - "clsid": "{LAU3_WP61_TER_3_C}", - "name": '3 x LAU-3 pod - 19 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 670.37, - } - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU-68 FFAR Mk5 HEAT_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk5, HEAT (TER)', - "weight": 378.5393312, - } - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = { - "clsid": "{LAU-68 FFAR WP156_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts M156, Wht Phos (TER)', - "weight": 408.0681704, - } - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = { - "clsid": "{LAU-68 FFAR Mk1 HE_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" FFAR, UnGd Rkts Mk1, HE (TER)', - "weight": 377.586788, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = { - "clsid": "{LAU-68 Hydra M151 HE_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M151, HE (TER)', - "weight": 387.2, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = { - "clsid": "{LAU-68 Hydra WP156_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M156, Wht Phos (TER)', - "weight": 390.98, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_ = { - "clsid": "{LAU-68 Hydra M257 PI_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M257, Para Illum (TER)', - "weight": 404, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_ = { - "clsid": "{LAU-68 Hydra M274 PS_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts M274, Practice Smk (TER)', - "weight": 387.2, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_ = { - "clsid": "{LAU-68 Hydra Mk1 Practice_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk1, Practice (TER)', - "weight": 360.11, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = { - "clsid": "{LAU-68 Hydra Mk5 HEAT_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk5, HEAT (TER)', - "weight": 353.81, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = { - "clsid": "{LAU-68 Hydra Mk61 Practice_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts Mk61, Practice (TER)', - "weight": 360.11, - } - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = { - "clsid": "{LAU-68 Hydra WTU1B Practice_TER_3_C}", - "name": '3 x LAU-68 pod - 7 x 2.75" Hydra, UnGd Rkts WTU-1/B, Practice (TER)', - "weight": 387.2, - } - _3_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_ = { - "clsid": "{Mk-20_TER_3_C}", - "name": "3 x Mk-20 Rockeye - 490lbs CBU, 247 x HEAT Bomblets (TER)", - "weight": 713.6, - } - _3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_ = { - "clsid": "{Mk-82 Snakeye_TER_3_C}", - "name": "3 x Mk-82 Snakeye - 500lb GP Bomb HD (TER)", - "weight": 770.6, - } - _3_x_Mk_82___500lb_GP_Bomb_LD__TER_ = { - "clsid": "{Mk-82_TER_3_C}", - "name": "3 x Mk-82 - 500lb GP Bomb LD (TER)", - "weight": 770.6, - } - _3_x_Mk_83___1000lb_GP_Bomb_LD__TER_ = { - "clsid": "{Mk-83_TER_3_C}", - "name": "3 x Mk-83 - 1000lb GP Bomb LD (TER)", - "weight": 1388.6, - } - _4_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__MER_ = { - "clsid": "{Mk-77 mod 1_MER_4_C}", - "name": "4 x Mk-77 mod 1 - 500lb Fire Bomb LD (MER)", - "weight": 1019.8, - } - _4_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_ = { - "clsid": "{Mk-82 Snakeye_MER_4_C}", - "name": "4 x Mk-82 Snakeye - 500lb GP Bomb HD (MER)", - "weight": 1063.8, - } - _4_x_Mk_82___500lb_GP_Bomb_LD__MER_ = { - "clsid": "{Mk-82_MER_4_C}", - "name": "4 x Mk-82 - 500lb GP Bomb LD (MER)", - "weight": 1063.8, - } - _5_x_AN_M57___250lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M57_MER_5_L}", - "name": "5 x AN-M57 - 250lb GP Bomb LD (MER)", - "weight": 664.8, - } - _5_x_AN_M57___250lb_GP_Bomb_LD__MER__ = { - "clsid": "{AN-M57_MER_5_R}", - "name": "5 x AN-M57 - 250lb GP Bomb LD (MER)", - "weight": 664.8, - } - _5_x_AN_M81___260lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M81_MER_5_L}", - "name": "5 x AN-M81 - 260lb GP Bomb LD (MER)", - "weight": 689.4696, - } - _5_x_AN_M81___260lb_GP_Bomb_LD__MER__ = { - "clsid": "{AN-M81_MER_5_R}", - "name": "5 x AN-M81 - 260lb GP Bomb LD (MER)", - "weight": 689.4696, - } - _5_x_AN_M88___220lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M88_MER_5_L}", - "name": "5 x AN-M88 - 220lb GP Bomb LD (MER)", - "weight": 590.132952, - } - _5_x_AN_M88___220lb_GP_Bomb_LD__MER__ = { - "clsid": "{AN-M88_MER_5_R}", - "name": "5 x AN-M88 - 220lb GP Bomb LD (MER)", - "weight": 590.132952, - } - _5_x_BDU_33___25lb_Practice_Bomb_LD__MER_ = { - "clsid": "{BDU-33_MER_5_L}", - "name": "5 x BDU-33 - 25lb Practice Bomb LD (MER)", - "weight": 156.3, - } - _5_x_BDU_33___25lb_Practice_Bomb_LD__MER__ = { - "clsid": "{BDU-33_MER_5_R}", - "name": "5 x BDU-33 - 25lb Practice Bomb LD (MER)", - "weight": 156.3, - } - _5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_ = { - "clsid": "{Mk-81SE_MER_5_L}", - "name": "5 x Mk-81 Snakeye - 250lb GP Bomb HD (MER)", - "weight": 666.79, - } - _5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER__ = { - "clsid": "{Mk-81SE_MER_5_R}", - "name": "5 x Mk-81 Snakeye - 250lb GP Bomb HD (MER)", - "weight": 666.79, - } - _5_x_Mk_81___250lb_GP_Bomb_LD__MER_ = { - "clsid": "{Mk-81_MER_5_L}", - "name": "5 x Mk-81 - 250lb GP Bomb LD (MER)", - "weight": 689.8, - } - _5_x_Mk_81___250lb_GP_Bomb_LD__MER__ = { - "clsid": "{Mk-81_MER_5_R}", - "name": "5 x Mk-81 - 250lb GP Bomb LD (MER)", - "weight": 689.8, - } - _6_x_AN_M57___250lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M57_MER_6_C}", - "name": "6 x AN-M57 - 250lb GP Bomb LD (MER)", - "weight": 777.8, - } - _6_x_AN_M81___260lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M81_MER_6_C}", - "name": "6 x AN-M81 - 260lb GP Bomb LD (MER)", - "weight": 807.40352, - } - _6_x_AN_M88___220lb_GP_Bomb_LD__MER_ = { - "clsid": "{AN-M88_MER_6_C}", - "name": "6 x AN-M88 - 220lb GP Bomb LD (MER)", - "weight": 688.1995424, - } - _6_x_BDU_33___25lb_Practice_Bomb_LD__MER_ = { - "clsid": "{BDU-33_MER_6_C}", - "name": "6 x BDU-33 - 25lb Practice Bomb LD (MER)", - "weight": 167.6, - } - _6_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_ = { - "clsid": "{Mk-81SE_MER_6_C}", - "name": "6 x Mk-81 Snakeye - 250lb GP Bomb HD (MER)", - "weight": 780.188, - } - _6_x_Mk_81___250lb_GP_Bomb_LD__MER_ = { - "clsid": "{Mk-81_MER_6_C}", - "name": "6 x Mk-81 - 250lb GP Bomb LD (MER)", - "weight": 807.8, - } - _6_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_ = { - "clsid": "{Mk-82 Snakeye_MER_6_C}", - "name": "6 x Mk-82 Snakeye - 500lb GP Bomb HD (MER)", - "weight": 1545.8, - } - _6_x_Mk_82___500lb_GP_Bomb_LD__MER_ = { - "clsid": "{Mk-82_MER_6_C}", - "name": "6 x Mk-82 - 500lb GP Bomb LD (MER)", - "weight": 1545.8, - } - - -inject_weapons(WeaponsA4EC) - - -@planemod -class A_4E_C(PlaneType): - id = "A-4E-C" - flyable = True - height = 4.57 - width = 8.38 - length = 12.22 - fuel_max = 2467.5454273299 - max_speed = 1082.88 - chaff = 30 - flare = 30 - charge_total = 60 - chaff_charge_size = 1 - flare_charge_size = 1 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 254 - - panel_radio = { - 1: { - "channels": { - 1: 264, - 2: 265, - 4: 254, - 8: 258, - 16: 267, - 17: 251, - 9: 262, - 18: 253, - 5: 250, - 10: 259, - 20: 252, - 11: 268, - 3: 256, - 6: 270, - 12: 269, - 13: 260, - 7: 257, - 14: 263, - 19: 266, - 15: 261, - }, - }, - } - - property_defaults: Dict[str, Any] = { - "HideECMPanel": False, - "Auto_Catapult_Power": False, - "Night_Vision": False, - "CBU2ATPP": 0, - "CBU2BATPP": 0, - "CMS_BURSTS": 1, - "CMS_BURST_INTERVAL": 1, - "CMS_SALVOS": 1, - "CMS_SALVO_INTERVAL": 1, - } - - class Properties: - class HideECMPanel: - id = "HideECMPanel" - - class Auto_Catapult_Power: - id = "Auto_Catapult_Power" - - class Night_Vision: - id = "Night_Vision" - - class CBU2ATPP: - id = "CBU2ATPP" - - class Values: - x_1_tube = 0 - x_2_tubes = 1 - x_3_tubes = 2 - x_4_tubes = 3 - x_6_tubes = 4 - x_17_tubes__salvo = 5 - - class CBU2BATPP: - id = "CBU2BATPP" - - class Values: - x_2_tubes = 0 - x_4_tubes = 1 - x_6_tubes = 2 - - class CMS_BURSTS: - id = "CMS_BURSTS" - - class Values: - x_1 = 1 - x_2 = 2 - x_3 = 3 - x_4 = 4 - - class CMS_BURST_INTERVAL: - id = "CMS_BURST_INTERVAL" - - class Values: - x_0_2_seconds = 1 - x_0_3_seconds = 2 - x_0_4_seconds = 3 - x_0_5_seconds = 4 - - class CMS_SALVOS: - id = "CMS_SALVOS" - - class Values: - x_8 = 1 - x_12 = 2 - x_16 = 3 - x_20 = 4 - x_24 = 5 - x_28 = 6 - x_32 = 7 - - class CMS_SALVO_INTERVAL: - id = "CMS_SALVO_INTERVAL" - - class Values: - x_2_seconds = 1 - x_4_seconds = 2 - x_6_seconds = 3 - x_8_seconds = 4 - x_10_seconds = 5 - x_12_seconds = 6 - x_14_seconds = 7 - - livery_name = "A-4E-C" # from type - - class Pylon1: - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 1, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 1, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P5_Sidewinder_IR_AAM = ( - 1, - Weapons.LAU_7_with_AIM_9P5_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P3_Sidewinder_IR_AAM = ( - 1, - WeaponsA4EC.LAU_7_with_AIM_9P3_Sidewinder_IR_AAM, - ) - LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_ = ( - 1, - WeaponsA4EC.LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_, - ) - LAU_7_with_AIM_9J_Sidewinder_IR_AAM = ( - 1, - WeaponsA4EC.LAU_7_with_AIM_9J_Sidewinder_IR_AAM, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 1, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 1, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 1, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 1, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 1, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU3_WP61 = (1, Weapons.LAU3_WP61) - LAU3_WP1B = (1, Weapons.LAU3_WP1B) - LAU3_HE5 = (1, Weapons.LAU3_HE5) - LAU3_WP156 = (1, Weapons.LAU3_WP156) - LAU3_HE151 = (1, Weapons.LAU3_HE151) - AGM_45A_Shrike_ARM = (1, Weapons.AGM_45A_Shrike_ARM) - AGM_45B_Shrike_ARM__Imp_ = (1, Weapons.AGM_45B_Shrike_ARM__Imp_) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 1, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_81___250lb_GP_Bomb_LD = (1, Weapons.Mk_81___250lb_GP_Bomb_LD) - Mk_81_Snakeye___250lb_GP_Bomb_HD = ( - 1, - WeaponsA4EC.Mk_81_Snakeye___250lb_GP_Bomb_HD, - ) - Mk_82___500lb_GP_Bomb_LD = (1, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (1, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_77_mod_1___500lb_Fire_Bomb_LD = ( - 1, - WeaponsA4EC.Mk_77_mod_1___500lb_Fire_Bomb_LD, - ) - AN_M30A1___100lb_GP_Bomb_LD = (1, Weapons.AN_M30A1___100lb_GP_Bomb_LD) - AN_M57___250lb_GP_Bomb_LD = (1, Weapons.AN_M57___250lb_GP_Bomb_LD) - AN_M64___500lb_GP_Bomb_LD = (1, Weapons.AN_M64___500lb_GP_Bomb_LD) - AN_M81___260lb_GP_Bomb_LD = (1, WeaponsA4EC.AN_M81___260lb_GP_Bomb_LD) - AN_M88___220lb_GP_Bomb_LD = (1, WeaponsA4EC.AN_M88___220lb_GP_Bomb_LD) - Smokewinder___red = (1, Weapons.Smokewinder___red) - Smokewinder___green = (1, Weapons.Smokewinder___green) - Smokewinder___blue = (1, Weapons.Smokewinder___blue) - Smokewinder___white = (1, Weapons.Smokewinder___white) - Smokewinder___yellow = (1, Weapons.Smokewinder___yellow) - Smokewinder___orange = (1, Weapons.Smokewinder___orange) - SUU_25_x_8_LUU_2___Target_Marker_Flares = ( - 1, - Weapons.SUU_25_x_8_LUU_2___Target_Marker_Flares, - ) - - # ERRR - - class Pylon2: - Fuel_Tank_300_gallons_ = (2, WeaponsA4EC.Fuel_Tank_300_gallons_) - Fuel_Tank_300_gallons__EMPTY__ = (2, WeaponsA4EC.Fuel_Tank_300_gallons__EMPTY__) - Fuel_Tank_150_gallons = (2, WeaponsA4EC.Fuel_Tank_150_gallons) - Fuel_Tank_150_gallons__EMPTY_ = (2, WeaponsA4EC.Fuel_Tank_150_gallons__EMPTY_) - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 2, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 2, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P5_Sidewinder_IR_AAM = ( - 2, - Weapons.LAU_7_with_AIM_9P5_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P3_Sidewinder_IR_AAM = ( - 2, - WeaponsA4EC.LAU_7_with_AIM_9P3_Sidewinder_IR_AAM, - ) - LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_ = ( - 2, - WeaponsA4EC.LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_, - ) - LAU_7_with_AIM_9J_Sidewinder_IR_AAM = ( - 2, - WeaponsA4EC.LAU_7_with_AIM_9J_Sidewinder_IR_AAM, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 2, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 2, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER__, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER__, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER__, - ) - LAU3_WP61 = (2, Weapons.LAU3_WP61) - LAU3_WP1B = (2, Weapons.LAU3_WP1B) - LAU3_HE5 = (2, Weapons.LAU3_HE5) - LAU3_WP156 = (2, Weapons.LAU3_WP156) - LAU3_HE151 = (2, Weapons.LAU3_HE151) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER__, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__ = ( - 2, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER__, - ) - AGM_45A_Shrike_ARM = (2, Weapons.AGM_45A_Shrike_ARM) - AGM_45B_Shrike_ARM__Imp_ = (2, Weapons.AGM_45B_Shrike_ARM__Imp_) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 2, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_81___250lb_GP_Bomb_LD = (2, Weapons.Mk_81___250lb_GP_Bomb_LD) - Mk_81_Snakeye___250lb_GP_Bomb_HD = ( - 2, - WeaponsA4EC.Mk_81_Snakeye___250lb_GP_Bomb_HD, - ) - Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (2, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (2, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (2, Weapons.Mk_84___2000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (2, Weapons.M117___750lb_GP_Bomb_LD) - Mk_77_mod_0___750lb_Fire_Bomb_LD = ( - 2, - WeaponsA4EC.Mk_77_mod_0___750lb_Fire_Bomb_LD, - ) - Mk_77_mod_1___500lb_Fire_Bomb_LD = ( - 2, - WeaponsA4EC.Mk_77_mod_1___500lb_Fire_Bomb_LD, - ) - AN_M30A1___100lb_GP_Bomb_LD = (2, Weapons.AN_M30A1___100lb_GP_Bomb_LD) - AN_M57___250lb_GP_Bomb_LD = (2, Weapons.AN_M57___250lb_GP_Bomb_LD) - AN_M64___500lb_GP_Bomb_LD = (2, Weapons.AN_M64___500lb_GP_Bomb_LD) - AN_M65___1000lb_GP_Bomb_LD = (2, Weapons.AN_M65___1000lb_GP_Bomb_LD) - AN_M81___260lb_GP_Bomb_LD = (2, WeaponsA4EC.AN_M81___260lb_GP_Bomb_LD) - AN_M88___220lb_GP_Bomb_LD = (2, WeaponsA4EC.AN_M88___220lb_GP_Bomb_LD) - CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE = ( - 2, - WeaponsA4EC.CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE, - ) - CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = ( - 2, - WeaponsA4EC.CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE, - ) - CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = ( - 2, - WeaponsA4EC.CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE, - ) - _2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER_ = ( - 2, - WeaponsA4EC._2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER_, - ) - _2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_ = ( - 2, - WeaponsA4EC._2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_, - ) - _2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_ = ( - 2, - WeaponsA4EC._2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER_, - ) - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_ = ( - 2, - WeaponsA4EC._2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_, - ) - _5_x_Mk_81___250lb_GP_Bomb_LD__MER_ = ( - 2, - WeaponsA4EC._5_x_Mk_81___250lb_GP_Bomb_LD__MER_, - ) - _5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_ = ( - 2, - WeaponsA4EC._5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_, - ) - _2_x_Mk_82___500lb_GP_Bomb_LD__TER_ = ( - 2, - WeaponsA4EC._2_x_Mk_82___500lb_GP_Bomb_LD__TER_, - ) - _2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_ = ( - 2, - WeaponsA4EC._2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_, - ) - _5_x_AN_M57___250lb_GP_Bomb_LD__MER_ = ( - 2, - WeaponsA4EC._5_x_AN_M57___250lb_GP_Bomb_LD__MER_, - ) - _2_x_AN_M57___250lb_GP_Bomb_LD__TER_ = ( - 2, - WeaponsA4EC._2_x_AN_M57___250lb_GP_Bomb_LD__TER_, - ) - _5_x_AN_M81___260lb_GP_Bomb_LD__MER_ = ( - 2, - WeaponsA4EC._5_x_AN_M81___260lb_GP_Bomb_LD__MER_, - ) - _5_x_AN_M88___220lb_GP_Bomb_LD__MER_ = ( - 2, - WeaponsA4EC._5_x_AN_M88___220lb_GP_Bomb_LD__MER_, - ) - _5_x_BDU_33___25lb_Practice_Bomb_LD__MER_ = ( - 2, - WeaponsA4EC._5_x_BDU_33___25lb_Practice_Bomb_LD__MER_, - ) - Mk4_HIPEG___Gunpod = (2, WeaponsA4EC.Mk4_HIPEG___Gunpod) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - Smokewinder___orange = (2, Weapons.Smokewinder___orange) - SUU_25_x_8_LUU_2___Target_Marker_Flares = ( - 2, - Weapons.SUU_25_x_8_LUU_2___Target_Marker_Flares, - ) - - # ERRR - - class Pylon3: - Fuel_Tank_400_gallons = (3, WeaponsA4EC.Fuel_Tank_400_gallons) - Fuel_Tank_300_gallons = (3, WeaponsA4EC.Fuel_Tank_300_gallons) - Fuel_Tank_150_gallons = (3, WeaponsA4EC.Fuel_Tank_150_gallons) - Fuel_Tank_400_gallons__EMPTY_ = (3, WeaponsA4EC.Fuel_Tank_400_gallons__EMPTY_) - Fuel_Tank_300_gallons__EMPTY_ = (3, WeaponsA4EC.Fuel_Tank_300_gallons__EMPTY_) - Fuel_Tank_150_gallons__EMPTY_ = (3, WeaponsA4EC.Fuel_Tank_150_gallons__EMPTY_) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 3, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 3, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER_, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER_, - ) - LAU3_WP156 = (3, Weapons.LAU3_WP156) - LAU3_HE5 = (3, Weapons.LAU3_HE5) - LAU3_WP61 = (3, Weapons.LAU3_WP61) - LAU3_WP1B = (3, Weapons.LAU3_WP1B) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_, - ) - _3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_, - ) - _3_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER_, - ) - LAU3_HE151 = (3, Weapons.LAU3_HE151) - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_, - ) - _3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = ( - 3, - WeaponsA4EC._3_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER_, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_ = ( - 3, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER_, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_81___250lb_GP_Bomb_LD = (3, Weapons.Mk_81___250lb_GP_Bomb_LD) - Mk_81_Snakeye___250lb_GP_Bomb_HD = ( - 3, - WeaponsA4EC.Mk_81_Snakeye___250lb_GP_Bomb_HD, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (3, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (3, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (3, Weapons.M117___750lb_GP_Bomb_LD) - Mk_77_mod_0___750lb_Fire_Bomb_LD = ( - 3, - WeaponsA4EC.Mk_77_mod_0___750lb_Fire_Bomb_LD, - ) - Mk_77_mod_1___500lb_Fire_Bomb_LD = ( - 3, - WeaponsA4EC.Mk_77_mod_1___500lb_Fire_Bomb_LD, - ) - AN_M30A1___100lb_GP_Bomb_LD = (3, Weapons.AN_M30A1___100lb_GP_Bomb_LD) - AN_M57___250lb_GP_Bomb_LD = (3, Weapons.AN_M57___250lb_GP_Bomb_LD) - AN_M64___500lb_GP_Bomb_LD = (3, Weapons.AN_M64___500lb_GP_Bomb_LD) - AN_M65___1000lb_GP_Bomb_LD = (3, Weapons.AN_M65___1000lb_GP_Bomb_LD) - AN_M66A2___2000lb_GP_Bomb_LD = (3, WeaponsA4EC.AN_M66A2___2000lb_GP_Bomb_LD) - AN_M81___260lb_GP_Bomb_LD = (3, WeaponsA4EC.AN_M81___260lb_GP_Bomb_LD) - AN_M88___220lb_GP_Bomb_LD = (3, WeaponsA4EC.AN_M88___220lb_GP_Bomb_LD) - _3_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_ = ( - 3, - WeaponsA4EC._3_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER_, - ) - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER___ = ( - 3, - WeaponsA4EC._2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER___, - ) - _6_x_Mk_81___250lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_Mk_81___250lb_GP_Bomb_LD__MER_, - ) - _6_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_ = ( - 3, - WeaponsA4EC._6_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER_, - ) - _6_x_Mk_82___500lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_Mk_82___500lb_GP_Bomb_LD__MER_, - ) - _4_x_Mk_82___500lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._4_x_Mk_82___500lb_GP_Bomb_LD__MER_, - ) - _3_x_Mk_82___500lb_GP_Bomb_LD__TER_ = ( - 3, - WeaponsA4EC._3_x_Mk_82___500lb_GP_Bomb_LD__TER_, - ) - _6_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_ = ( - 3, - WeaponsA4EC._6_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_, - ) - _4_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_ = ( - 3, - WeaponsA4EC._4_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__MER_, - ) - _3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_ = ( - 3, - WeaponsA4EC._3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER_, - ) - _3_x_Mk_83___1000lb_GP_Bomb_LD__TER_ = ( - 3, - WeaponsA4EC._3_x_Mk_83___1000lb_GP_Bomb_LD__TER_, - ) - _2_x_Mk_83___1000lb_GP_Bomb_LD__TER_ = ( - 3, - WeaponsA4EC._2_x_Mk_83___1000lb_GP_Bomb_LD__TER_, - ) - _2_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__TER___ = ( - 3, - WeaponsA4EC._2_x_Mk_77_mod_1___500lb_Fire_Bomb_LD__TER___, - ) - _6_x_AN_M57___250lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_AN_M57___250lb_GP_Bomb_LD__MER_, - ) - _3_x_AN_M57___250lb_GP_Bomb_LD__TER_ = ( - 3, - WeaponsA4EC._3_x_AN_M57___250lb_GP_Bomb_LD__TER_, - ) - _6_x_AN_M81___260lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_AN_M81___260lb_GP_Bomb_LD__MER_, - ) - _6_x_AN_M88___220lb_GP_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_AN_M88___220lb_GP_Bomb_LD__MER_, - ) - _6_x_BDU_33___25lb_Practice_Bomb_LD__MER_ = ( - 3, - WeaponsA4EC._6_x_BDU_33___25lb_Practice_Bomb_LD__MER_, - ) - Mk4_HIPEG___Gunpod = (3, WeaponsA4EC.Mk4_HIPEG___Gunpod) - Smokewinder___red = (3, Weapons.Smokewinder___red) - Smokewinder___green = (3, Weapons.Smokewinder___green) - Smokewinder___blue = (3, Weapons.Smokewinder___blue) - Smokewinder___white = (3, Weapons.Smokewinder___white) - Smokewinder___yellow = (3, Weapons.Smokewinder___yellow) - Smokewinder___orange = (3, Weapons.Smokewinder___orange) - SUU_25_x_8_LUU_2___Target_Marker_Flares = ( - 3, - Weapons.SUU_25_x_8_LUU_2___Target_Marker_Flares, - ) - - # ERRR - - class Pylon4: - Fuel_Tank_300_gallons_ = (4, WeaponsA4EC.Fuel_Tank_300_gallons_) - Fuel_Tank_300_gallons__EMPTY__ = (4, WeaponsA4EC.Fuel_Tank_300_gallons__EMPTY__) - Fuel_Tank_150_gallons = (4, WeaponsA4EC.Fuel_Tank_150_gallons) - Fuel_Tank_150_gallons__EMPTY_ = (4, WeaponsA4EC.Fuel_Tank_150_gallons__EMPTY_) - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 4, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 4, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P5_Sidewinder_IR_AAM = ( - 4, - Weapons.LAU_7_with_AIM_9P5_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P3_Sidewinder_IR_AAM = ( - 4, - WeaponsA4EC.LAU_7_with_AIM_9P3_Sidewinder_IR_AAM, - ) - LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_ = ( - 4, - WeaponsA4EC.LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_, - ) - LAU_7_with_AIM_9J_Sidewinder_IR_AAM = ( - 4, - WeaponsA4EC.LAU_7_with_AIM_9J_Sidewinder_IR_AAM, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 4, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 4, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts__Mk5__HEAT__TER___, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__M156__Wht_Phos__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts__Mk1__HE__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT__TER___, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___, - ) - _2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_MK_71__HE_FRAG__TER___, - ) - LAU3_WP61 = (4, Weapons.LAU3_WP61) - LAU3_WP1B = (4, Weapons.LAU3_WP1B) - LAU3_HE5 = (4, Weapons.LAU3_HE5) - LAU3_WP156 = (4, Weapons.LAU3_WP156) - LAU3_HE151 = (4, Weapons.LAU3_HE151) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice__TER___, - ) - _2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___ = ( - 4, - WeaponsA4EC._2_x_LAU_3_pod___19_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice__TER___, - ) - AGM_45A_Shrike_ARM = (4, Weapons.AGM_45A_Shrike_ARM) - AGM_45B_Shrike_ARM__Imp_ = (4, Weapons.AGM_45B_Shrike_ARM__Imp_) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_81___250lb_GP_Bomb_LD = (4, Weapons.Mk_81___250lb_GP_Bomb_LD) - Mk_81_Snakeye___250lb_GP_Bomb_HD = ( - 4, - WeaponsA4EC.Mk_81_Snakeye___250lb_GP_Bomb_HD, - ) - Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (4, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (4, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (4, Weapons.Mk_84___2000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (4, Weapons.M117___750lb_GP_Bomb_LD) - Mk_77_mod_0___750lb_Fire_Bomb_LD = ( - 4, - WeaponsA4EC.Mk_77_mod_0___750lb_Fire_Bomb_LD, - ) - Mk_77_mod_1___500lb_Fire_Bomb_LD = ( - 4, - WeaponsA4EC.Mk_77_mod_1___500lb_Fire_Bomb_LD, - ) - AN_M30A1___100lb_GP_Bomb_LD = (4, Weapons.AN_M30A1___100lb_GP_Bomb_LD) - AN_M57___250lb_GP_Bomb_LD = (4, Weapons.AN_M57___250lb_GP_Bomb_LD) - AN_M64___500lb_GP_Bomb_LD = (4, Weapons.AN_M64___500lb_GP_Bomb_LD) - AN_M65___1000lb_GP_Bomb_LD = (4, Weapons.AN_M65___1000lb_GP_Bomb_LD) - AN_M81___260lb_GP_Bomb_LD = (4, WeaponsA4EC.AN_M81___260lb_GP_Bomb_LD) - AN_M88___220lb_GP_Bomb_LD = (4, WeaponsA4EC.AN_M88___220lb_GP_Bomb_LD) - CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE = ( - 4, - WeaponsA4EC.CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE, - ) - CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = ( - 4, - WeaponsA4EC.CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE, - ) - CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE = ( - 4, - WeaponsA4EC.CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE, - ) - _2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER__ = ( - 4, - WeaponsA4EC._2_x_CBU_1_A_pod___19_x_tubes_of_Bomblets_BLU_4B_x_27__HE__TER__, - ) - _2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__ = ( - 4, - WeaponsA4EC._2_x_CBU_2_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__, - ) - _2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__ = ( - 4, - WeaponsA4EC._2_x_CBU_2B_A_pod___19_x_tubes_of_Bomblets_BLU_3B_x_19__HE__TER__, - ) - _2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER__ = ( - 4, - WeaponsA4EC._2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets__TER__, - ) - _5_x_Mk_81___250lb_GP_Bomb_LD__MER__ = ( - 4, - WeaponsA4EC._5_x_Mk_81___250lb_GP_Bomb_LD__MER__, - ) - _5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER__ = ( - 4, - WeaponsA4EC._5_x_Mk_81_Snakeye___250lb_GP_Bomb_HD__MER__, - ) - _2_x_Mk_82___500lb_GP_Bomb_LD__TER__ = ( - 4, - WeaponsA4EC._2_x_Mk_82___500lb_GP_Bomb_LD__TER__, - ) - _2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER__ = ( - 4, - WeaponsA4EC._2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD__TER__, - ) - _5_x_AN_M57___250lb_GP_Bomb_LD__MER__ = ( - 4, - WeaponsA4EC._5_x_AN_M57___250lb_GP_Bomb_LD__MER__, - ) - _2_x_AN_M57___250lb_GP_Bomb_LD__TER__ = ( - 4, - WeaponsA4EC._2_x_AN_M57___250lb_GP_Bomb_LD__TER__, - ) - _5_x_AN_M81___260lb_GP_Bomb_LD__MER__ = ( - 4, - WeaponsA4EC._5_x_AN_M81___260lb_GP_Bomb_LD__MER__, - ) - _5_x_AN_M88___220lb_GP_Bomb_LD__MER__ = ( - 4, - WeaponsA4EC._5_x_AN_M88___220lb_GP_Bomb_LD__MER__, - ) - _5_x_BDU_33___25lb_Practice_Bomb_LD__MER__ = ( - 4, - WeaponsA4EC._5_x_BDU_33___25lb_Practice_Bomb_LD__MER__, - ) - Mk4_HIPEG___Gunpod = (4, WeaponsA4EC.Mk4_HIPEG___Gunpod) - Smokewinder___red = (4, Weapons.Smokewinder___red) - Smokewinder___green = (4, Weapons.Smokewinder___green) - Smokewinder___blue = (4, Weapons.Smokewinder___blue) - Smokewinder___white = (4, Weapons.Smokewinder___white) - Smokewinder___yellow = (4, Weapons.Smokewinder___yellow) - Smokewinder___orange = (4, Weapons.Smokewinder___orange) - SUU_25_x_8_LUU_2___Target_Marker_Flares = ( - 4, - Weapons.SUU_25_x_8_LUU_2___Target_Marker_Flares, - ) - - # ERRR - - class Pylon5: - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 5, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 5, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P5_Sidewinder_IR_AAM = ( - 5, - Weapons.LAU_7_with_AIM_9P5_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9P3_Sidewinder_IR_AAM = ( - 5, - WeaponsA4EC.LAU_7_with_AIM_9P3_Sidewinder_IR_AAM, - ) - LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_ = ( - 5, - WeaponsA4EC.LAU_7_with_AN_ASQ_T50_TCTS_Pod___ACMI_Pod_, - ) - LAU_7_with_AIM_9J_Sidewinder_IR_AAM = ( - 5, - WeaponsA4EC.LAU_7_with_AIM_9J_Sidewinder_IR_AAM, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 5, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 5, - Weapons.LAU_3_pod___19_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 5, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU3_WP61 = (5, Weapons.LAU3_WP61) - LAU3_WP1B = (5, Weapons.LAU3_WP1B) - LAU3_HE5 = (5, Weapons.LAU3_HE5) - LAU3_WP156 = (5, Weapons.LAU3_WP156) - LAU3_HE151 = (5, Weapons.LAU3_HE151) - AGM_45A_Shrike_ARM = (5, Weapons.AGM_45A_Shrike_ARM) - AGM_45B_Shrike_ARM__Imp_ = (5, Weapons.AGM_45B_Shrike_ARM__Imp_) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 5, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_81___250lb_GP_Bomb_LD = (5, Weapons.Mk_81___250lb_GP_Bomb_LD) - Mk_81_Snakeye___250lb_GP_Bomb_HD = ( - 5, - WeaponsA4EC.Mk_81_Snakeye___250lb_GP_Bomb_HD, - ) - Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (5, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_77_mod_1___500lb_Fire_Bomb_LD = ( - 5, - WeaponsA4EC.Mk_77_mod_1___500lb_Fire_Bomb_LD, - ) - AN_M30A1___100lb_GP_Bomb_LD = (5, Weapons.AN_M30A1___100lb_GP_Bomb_LD) - AN_M57___250lb_GP_Bomb_LD = (5, Weapons.AN_M57___250lb_GP_Bomb_LD) - AN_M64___500lb_GP_Bomb_LD = (5, Weapons.AN_M64___500lb_GP_Bomb_LD) - AN_M81___260lb_GP_Bomb_LD = (5, WeaponsA4EC.AN_M81___260lb_GP_Bomb_LD) - AN_M88___220lb_GP_Bomb_LD = (5, WeaponsA4EC.AN_M88___220lb_GP_Bomb_LD) - Smokewinder___red = (5, Weapons.Smokewinder___red) - Smokewinder___green = (5, Weapons.Smokewinder___green) - Smokewinder___blue = (5, Weapons.Smokewinder___blue) - Smokewinder___white = (5, Weapons.Smokewinder___white) - Smokewinder___yellow = (5, Weapons.Smokewinder___yellow) - Smokewinder___orange = (5, Weapons.Smokewinder___orange) - SUU_25_x_8_LUU_2___Target_Marker_Flares = ( - 5, - Weapons.SUU_25_x_8_LUU_2___Target_Marker_Flares, - ) - - # ERRR - - pylons: Set[int] = {1, 2, 3, 4, 5} - - tasks = [ - task.CAP, - task.CAS, - task.SEAD, - task.Reconnaissance, - task.GroundAttack, - task.AFAC, - task.RunwayAttack, - task.AntishipStrike, - task.Refueling, - task.Escort, - ] - task_default = task.CAS diff --git a/pydcs_extensions/f104/__init__.py b/pydcs_extensions/f104/__init__.py deleted file mode 100644 index 4cf87dbc1..000000000 --- a/pydcs_extensions/f104/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .f104 import * diff --git a/pydcs_extensions/f104/f104.py b/pydcs_extensions/f104/f104.py deleted file mode 100644 index 21621e92f..000000000 --- a/pydcs_extensions/f104/f104.py +++ /dev/null @@ -1,1007 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsF104: - LAU_115C_2_AIM_9L = { - "clsid": "{VSN_F104_LAU115C_AIM9L}", - "name": "LAU-115C 2*AIM-9L", - "weight": 332, - } - LAU_115C_2_AIM_9P = { - "clsid": "{VSN_F104_LAU115C_AIM9P}", - "name": "LAU-115C 2*AIM-9P", - "weight": 332, - } - VSN_F104G_L_PTB = {"clsid": "VSN_F104G_L_PTB", "name": "500L Tank L", "weight": 632} - VSN_F104G_L_PTB_ = { - "clsid": "VSN_F104G_L_PTB", - "name": "500L Tank L", - "weight": 632, - } - VSN_F104G_L_PTB__ = { - "clsid": "VSN_F104G_L_PTB", - "name": "500L Tank L", - "weight": 632, - } - VSN_F104G_PTB = {"clsid": "VSN_F104G_PTB", "name": "500L Tank", "weight": 632} - VSN_F104G_PTB_ = {"clsid": "VSN_F104G_PTB", "name": "500L Tank", "weight": 632} - VSN_F104G_PTB__ = {"clsid": "VSN_F104G_PTB", "name": "500L Tank", "weight": 632} - VSN_F104G_R_PTB = {"clsid": "VSN_F104G_R_PTB", "name": "500L Tank R", "weight": 632} - VSN_F104G_R_PTB_ = { - "clsid": "VSN_F104G_R_PTB", - "name": "500L Tank R", - "weight": 632, - } - VSN_F104G_R_PTB__ = { - "clsid": "VSN_F104G_R_PTB", - "name": "500L Tank R", - "weight": 632, - } - - -inject_weapons(WeaponsF104) - - -@planemod -class VSN_F104C(PlaneType): - id = "VSN_F104C" - flyable = True - height = 4.09 - width = 6.36 - length = 16.66 - fuel_max = 2641 - max_speed = 2336.4 - chaff = 30 - flare = 15 - charge_total = 60 - chaff_charge_size = 1 - flare_charge_size = 2 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - - livery_name = "VSN_F104C" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - LAU_138_AIM_9L = (2, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (2, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (2, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (2, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - VSN_F104G_L_PTB = (2, WeaponsF104.VSN_F104G_L_PTB) - - class Pylon4: - Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 4, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 4, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (4, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (4, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (4, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9L_Sidewinder_IR_AAM = (4, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (4, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (4, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (4, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 4, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 4, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81___ = (4, Weapons._2_Mk_81___) - Mk_81___250lb_GP_Bomb_LD = (4, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (4, Weapons.M117___750lb_GP_Bomb_LD) - Kormoran___ASM = (4, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (4, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (4, WeaponsF104.VSN_F104G_PTB) - - class Pylon6: - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 6, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - TER_9A_with_3_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.TER_9A_with_3_x_BDU_33___25lb_Practice_Bomb_LD, - ) - LAU_105_2_AIM_9P5 = (6, Weapons.LAU_105_2_AIM_9P5) - LAU_115C_2_AIM_9L = (6, WeaponsF104.LAU_115C_2_AIM_9L) - LAU_115C_2_AIM_9P = (6, WeaponsF104.LAU_115C_2_AIM_9P) - - class Pylon8: - Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 8, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 8, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (8, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (8, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9L_Sidewinder_IR_AAM = (8, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (8, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (8, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (8, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 8, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 8, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81 = (8, Weapons._2_Mk_81) - Mk_81___250lb_GP_Bomb_LD = (8, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (8, Weapons.M117___750lb_GP_Bomb_LD) - Kormoran___ASM = (8, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (8, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (8, WeaponsF104.VSN_F104G_PTB) - - class Pylon10: - LAU_138_AIM_9L = (10, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (10, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (10, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (10, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - VSN_F104G_R_PTB = (10, WeaponsF104.VSN_F104G_R_PTB) - - class Pylon11: - L_081_Fantasmagoria_ELINT_pod = (11, Weapons.L_081_Fantasmagoria_ELINT_pod) - - pylons: Set[int] = {1, 2, 4, 6, 8, 10, 11} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.RunwayAttack, - task.AntishipStrike, - ] - task_default = task.FighterSweep - - -@planemod -class VSN_F104G(PlaneType): - id = "VSN_F104G" - flyable = True - height = 4.09 - width = 6.36 - length = 16.66 - fuel_max = 2644 - max_speed = 2336.4 - chaff = 30 - flare = 15 - charge_total = 60 - chaff_charge_size = 1 - flare_charge_size = 2 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - - livery_name = "VSN_F104G" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - LAU_138_AIM_9L = (2, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (2, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (2, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (2, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - VSN_F104G_L_PTB = (2, WeaponsF104.VSN_F104G_L_PTB) - - class Pylon4: - Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 4, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 4, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (4, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (4, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (4, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9L_Sidewinder_IR_AAM = (4, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (4, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (4, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (4, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 4, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 4, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81___ = (4, Weapons._2_Mk_81___) - Mk_81___250lb_GP_Bomb_LD = (4, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (4, Weapons.M117___750lb_GP_Bomb_LD) - Kormoran___ASM = (4, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (4, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (4, WeaponsF104.VSN_F104G_PTB) - - class Pylon5: - AIM_9L_Sidewinder_IR_AAM = (5, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (5, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (5, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (5, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon6: - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 6, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - TER_9A_with_3_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.TER_9A_with_3_x_BDU_33___25lb_Practice_Bomb_LD, - ) - - class Pylon7: - AIM_9L_Sidewinder_IR_AAM = (7, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (7, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (7, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (7, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon8: - Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 8, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 8, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (8, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (8, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9L_Sidewinder_IR_AAM = (8, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (8, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (8, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (8, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 8, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 8, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81 = (8, Weapons._2_Mk_81) - Mk_81___250lb_GP_Bomb_LD = (8, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (8, Weapons.M117___750lb_GP_Bomb_LD) - Kormoran___ASM = (8, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (8, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (8, WeaponsF104.VSN_F104G_PTB) - - class Pylon10: - LAU_138_AIM_9L = (10, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (10, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (10, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (10, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - VSN_F104G_R_PTB = (10, WeaponsF104.VSN_F104G_R_PTB) - - class Pylon11: - L_081_Fantasmagoria_ELINT_pod = (11, Weapons.L_081_Fantasmagoria_ELINT_pod) - - pylons: Set[int] = {1, 2, 4, 5, 6, 7, 8, 10, 11} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.RunwayAttack, - task.AntishipStrike, - ] - task_default = task.FighterSweep - - -@planemod -class VSN_F104S(PlaneType): - id = "VSN_F104S" - flyable = True - height = 4.09 - width = 6.36 - length = 16.66 - fuel_max = 2641 - max_speed = 2336.4 - chaff = 30 - flare = 15 - charge_total = 60 - chaff_charge_size = 1 - flare_charge_size = 2 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - - livery_name = "VSN_F104S" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - AIM_9M_Sidewinder_IR_AAM = (2, Weapons.AIM_9M_Sidewinder_IR_AAM) - LAU_138_AIM_9L = (2, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (2, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (2, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (2, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - VSN_F104G_L_PTB = (2, WeaponsF104.VSN_F104G_L_PTB) - - class Pylon3: - AIM_9B_Sidewinder_IR_AAM = (3, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (3, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9M_Sidewinder_IR_AAM = (3, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (3, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (3, Weapons.AIM_9P5_Sidewinder_IR_AAM) - AIM_7F_Sparrow_Semi_Active_Radar = (3, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - - class Pylon4: - AIM_9M_Sidewinder_IR_AAM = (4, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (4, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (4, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (4, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (4, Weapons.AIM_9P5_Sidewinder_IR_AAM) - VSN_F104G_PTB = (4, WeaponsF104.VSN_F104G_PTB) - - class Pylon5: - AIM_9M_Sidewinder_IR_AAM = (5, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (5, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (5, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (5, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (5, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon6: - AIM_9M_Sidewinder_IR_AAM = (6, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (6, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (6, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (6, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (6, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon7: - AIM_9M_Sidewinder_IR_AAM = (7, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (7, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (7, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (7, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (7, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon8: - AIM_9M_Sidewinder_IR_AAM = (8, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (8, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (8, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (8, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (8, Weapons.AIM_9P5_Sidewinder_IR_AAM) - VSN_F104G_PTB = (8, WeaponsF104.VSN_F104G_PTB) - - class Pylon9: - AIM_9B_Sidewinder_IR_AAM = (9, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (9, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9M_Sidewinder_IR_AAM = (9, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (9, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (9, Weapons.AIM_9P5_Sidewinder_IR_AAM) - AIM_7F_Sparrow_Semi_Active_Radar = (9, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - - class Pylon10: - AIM_9M_Sidewinder_IR_AAM = (10, Weapons.AIM_9M_Sidewinder_IR_AAM) - LAU_138_AIM_9L = (10, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (10, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (10, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (10, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - VSN_F104G_R_PTB = (10, WeaponsF104.VSN_F104G_R_PTB) - - class Pylon11: - L_081_Fantasmagoria_ELINT_pod = (11, Weapons.L_081_Fantasmagoria_ELINT_pod) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.RunwayAttack, - task.AntishipStrike, - ] - task_default = task.FighterSweep - - -@planemod -class VSN_F104S_AG(PlaneType): - id = "VSN_F104S_AG" - flyable = True - height = 4.09 - width = 6.36 - length = 16.66 - fuel_max = 2644 - max_speed = 2336.4 - chaff = 30 - flare = 15 - charge_total = 60 - chaff_charge_size = 1 - flare_charge_size = 2 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - - livery_name = "VSN_F104S_AG" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - LAU_138_AIM_9L = (2, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (2, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (2, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (2, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - VSN_F104G_L_PTB = (2, WeaponsF104.VSN_F104G_L_PTB) - - class Pylon3: - LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_ = ( - 3, - Weapons.LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 3, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - CBU_97___10_x_SFW_Cluster_Bomb = (3, Weapons.CBU_97___10_x_SFW_Cluster_Bomb) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 3, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (3, Weapons.B_8M1___20_S_8OFP2) - AIM_9L_Sidewinder_IR_AAM = (3, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (3, Weapons.AIM_9B_Sidewinder_IR_AAM) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 3, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Kormoran___ASM = (3, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (3, Weapons.AGM_119B_Penguin_ASM) - - class Pylon4: - LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_ = ( - 4, - Weapons.LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 4, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 4, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 4, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - CBU_97___10_x_SFW_Cluster_Bomb = (4, Weapons.CBU_97___10_x_SFW_Cluster_Bomb) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 4, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (4, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (4, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (4, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 4, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 4, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9M_Sidewinder_IR_AAM = (4, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (4, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (4, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (4, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (4, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 4, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 4, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 4, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 4, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 4, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81 = (4, Weapons._2_Mk_81) - Mk_81___250lb_GP_Bomb_LD = (4, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (4, Weapons.M117___750lb_GP_Bomb_LD) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 4, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Kormoran___ASM = (4, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (4, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (4, WeaponsF104.VSN_F104G_PTB) - - class Pylon5: - AIM_9M_Sidewinder_IR_AAM = (5, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (5, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (5, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (5, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (5, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon6: - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - - class Pylon7: - AIM_9M_Sidewinder_IR_AAM = (7, Weapons.AIM_9M_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (7, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (7, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (7, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (7, Weapons.AIM_9P5_Sidewinder_IR_AAM) - - class Pylon8: - LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_ = ( - 8, - Weapons.LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 8, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 8, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 8, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - CBU_97___10_x_SFW_Cluster_Bomb = (8, Weapons.CBU_97___10_x_SFW_Cluster_Bomb) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 8, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (8, Weapons.B_8M1___20_S_8OFP2) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (8, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 8, - Weapons.BRU_33_with_2_x_LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 8, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - AIM_9B_Sidewinder_IR_AAM = (8, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (8, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (8, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (8, Weapons.AIM_9P5_Sidewinder_IR_AAM) - MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD = ( - 8, - Weapons.MER2_with_2_x_Mk_82___500lb_GP_Bombs_LD, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 8, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 8, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD = ( - 8, - Weapons.BRU_42_with_3_x_Mk_81___250lb_GP_Bombs_LD, - ) - _2_Mk_81 = (8, Weapons._2_Mk_81) - Mk_81___250lb_GP_Bomb_LD = (8, Weapons.Mk_81___250lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (8, Weapons.M117___750lb_GP_Bomb_LD) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 8, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Kormoran___ASM = (8, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (8, Weapons.AGM_119B_Penguin_ASM) - VSN_F104G_PTB = (8, WeaponsF104.VSN_F104G_PTB) - - class Pylon9: - LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_ = ( - 9, - Weapons.LAU_117_with_AGM_65D___Maverick_D__IIR_ASM_, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 9, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 9, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 9, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BL_755_CBU___450kg__147_Frag_Pen_bomblets = ( - 9, - Weapons.BL_755_CBU___450kg__147_Frag_Pen_bomblets, - ) - CBU_97___10_x_SFW_Cluster_Bomb = (9, Weapons.CBU_97___10_x_SFW_Cluster_Bomb) - S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__ = ( - 9, - Weapons.S_24B___240mm_UnGd_Rkt__235kg__HE_Frag___Low_Smk__, - ) - B_8M1___20_S_8OFP2 = (9, Weapons.B_8M1___20_S_8OFP2) - AIM_9P_Sidewinder_IR_AAM = (9, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (9, Weapons.AIM_9P5_Sidewinder_IR_AAM) - AIM_9L_Sidewinder_IR_AAM = (9, Weapons.AIM_9L_Sidewinder_IR_AAM) - AIM_9B_Sidewinder_IR_AAM = (9, Weapons.AIM_9B_Sidewinder_IR_AAM) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 9, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Kormoran___ASM = (9, Weapons.Kormoran___ASM) - AGM_119B_Penguin_ASM = (9, Weapons.AGM_119B_Penguin_ASM) - - class Pylon10: - LAU_138_AIM_9L = (10, Weapons.LAU_138_AIM_9L) - AIM_9B_Sidewinder_IR_AAM = (10, Weapons.AIM_9B_Sidewinder_IR_AAM) - AIM_9P_Sidewinder_IR_AAM = (10, Weapons.AIM_9P_Sidewinder_IR_AAM) - AIM_9P5_Sidewinder_IR_AAM = (10, Weapons.AIM_9P5_Sidewinder_IR_AAM) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - VSN_F104G_R_PTB = (10, WeaponsF104.VSN_F104G_R_PTB) - - class Pylon11: - L_081_Fantasmagoria_ELINT_pod = (11, Weapons.L_081_Fantasmagoria_ELINT_pod) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.RunwayAttack, - task.AntishipStrike, - ] - task_default = task.FighterSweep diff --git a/pydcs_extensions/f22a/__init__.py b/pydcs_extensions/f22a/__init__.py deleted file mode 100644 index d2fe9b7fc..000000000 --- a/pydcs_extensions/f22a/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .f22a import * diff --git a/pydcs_extensions/f22a/f22a.py b/pydcs_extensions/f22a/f22a.py deleted file mode 100644 index 6e810fb62..000000000 --- a/pydcs_extensions/f22a/f22a.py +++ /dev/null @@ -1,95 +0,0 @@ -from typing import Any, Dict, Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class F22AWeapons: - AIM_9XX = {"clsid": "{AIM-9XX}", "name": "AIM-9XX", "weight": 85} - AIM_120D = {"clsid": "{AIM-120D}", "name": "AIM-120D", "weight": 152} - - -inject_weapons(F22AWeapons) - - -@planemod -class F_22A(PlaneType): - id = "F-22A" - flyable = True - height = 4.88 - width = 13.05 - length = 19.1 - fuel_max = 6103 - max_speed = 2649.996 - chaff = 120 - flare = 120 - charge_total = 240 - chaff_charge_size = 1 - flare_charge_size = 2 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - property_defaults: Dict[str, Any] = { - "BAY_DOOR_OPTION": False, - } - - class Properties: - class BAY_DOOR_OPTION: - id = "BAY_DOOR_OPTION" - - livery_name = "F-22A" # from type - - class Pylon1: - AIM_9X_Sidewinder_IR_AAM = (1, Weapons.AIM_9X_Sidewinder_IR_AAM) - AIM_9XX = (1, F22AWeapons.AIM_9XX) - - class Pylon2: - Fuel_tank_610_gal = (2, Weapons.Fuel_tank_610_gal) - - class Pylon3: - AIM_120D = (3, F22AWeapons.AIM_120D) - - class Pylon4: - AIM_120D = (4, F22AWeapons.AIM_120D) - - class Pylon5: - AIM_120D = (5, F22AWeapons.AIM_120D) - - class Pylon6: - Smokewinder___red = (6, Weapons.Smokewinder___red) - Smokewinder___green = (6, Weapons.Smokewinder___green) - Smokewinder___blue = (6, Weapons.Smokewinder___blue) - Smokewinder___white = (6, Weapons.Smokewinder___white) - Smokewinder___yellow = (6, Weapons.Smokewinder___yellow) - - class Pylon7: - AIM_120D = (7, F22AWeapons.AIM_120D) - - class Pylon8: - AIM_120D = (8, F22AWeapons.AIM_120D) - - class Pylon9: - AIM_120D = (9, F22AWeapons.AIM_120D) - - class Pylon10: - Fuel_tank_610_gal = (10, Weapons.Fuel_tank_610_gal) - - class Pylon11: - AIM_9X_Sidewinder_IR_AAM = (11, Weapons.AIM_9X_Sidewinder_IR_AAM) - AIM_9XX = (11, F22AWeapons.AIM_9XX) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - ] - task_default = task.CAP diff --git a/pydcs_extensions/f4/__init__.py b/pydcs_extensions/f4/__init__.py deleted file mode 100644 index b8b5b9bc1..000000000 --- a/pydcs_extensions/f4/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .f4 import * diff --git a/pydcs_extensions/f4/f4.py b/pydcs_extensions/f4/f4.py deleted file mode 100644 index e2e895383..000000000 --- a/pydcs_extensions/f4/f4.py +++ /dev/null @@ -1,768 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsF4: - F4B_Gunpod_w_SAPHEI_T = { - "clsid": "{VSN_F4B_Equalizer}", - "name": "F4B Gunpod w/SAPHEI-T", - "weight": 244.46, - } - F4B_SUU_23_Gun_Pod = { - "clsid": "{VSN_F4B_Gunpod}", - "name": "F4B SUU-23 Gun Pod", - "weight": 112.35, - } - LAU_105_2_AIM_9J = { - "clsid": "{VSN_F4B_LAU105_AIM9J}", - "name": "LAU-105 2*AIM-9J", - "weight": 332, - } - LAU_105_2_AIM_9JULI = { - "clsid": "{VSN_F4B_LAU105_AIM9JULI}", - "name": "LAU-105 2*AIM-9JULI", - "weight": 332, - } - VSN_F4B_C2_PTB = { - "clsid": "VSN_F4B_C2_PTB", - "name": "Fuel tank Center 370 Gal", - "weight": 1240, - } - VSN_F4EC_PTB = { - "clsid": "VSN_F4EC_PTB", - "name": "Fuel tank Center 600 Gal", - "weight": 1980, - } - VSN_F4EL_PTB = { - "clsid": "VSN_F4EL_PTB", - "name": "Fuel tank Wing L 370 Gal", - "weight": 1240, - } - VSN_F4ER_PTB = { - "clsid": "VSN_F4ER_PTB", - "name": "Fuel tank Wing R 370 Gal", - "weight": 1240, - } - F4B_LAU105_AIM9J_2_BRU42A_M117_3 = { - "clsid": "{F4B_LAU105_AIM9J_2_BRU42A_M117_3}", - "name": "F4B_LAU105_AIM9J_2_BRU42A_M117_3", - "weight": 332, - } - F4B_LAU105_AIM9J_2_BRU42A_MK82_3 = { - "clsid": "{F4B_LAU105_AIM9J_2_BRU42A_MK82_3}", - "name": "F4B_LAU105_AIM9J_2_BRU42A_MK82_3", - "weight": 332, - } - F4B_LAU105_AIM9J_2_MER_MK20_3 = { - "clsid": "{F4B_LAU105_AIM9J_2_MER_MK20_3}", - "name": "F4B_LAU105_AIM9J_2_MER_MK20_3", - "weight": 332, - } - F4B_LAU105_AIM9J_2_TER9A_MK82SE_3 = { - "clsid": "{F4B_LAU105_AIM9J_2_TER9A_MK82SE_3}", - "name": "F4B_LAU105_AIM9J_2_TER9A_MK82SE_3", - "weight": 332, - } - BRU_42A_M117_3_LAU105_AIM9J_2 = { - "clsid": "{F4B_BRU42A_M117_3_LAU105_AIM9J_2}", - "name": "BRU 42A M117*3 LAU105 AIM9J*2", - "weight": 1500, - } - BRU_42A_MK82_3_LAU105_AIM9J_2 = { - "clsid": "{F4B_BRU42A_MK82_3_LAU105_AIM9J_2}", - "name": "BRU 42A MK82*3 LAU105 AIM9J*2", - "weight": 1500, - } - - -inject_weapons(WeaponsF4) - - -@planemod -class VSN_F4B(PlaneType): - id = "VSN_F4B" - flyable = True - height = 5.02 - width = 11.71 - length = 19.2 - fuel_max = 6416 - max_speed = 2545.2 - chaff = 48 - flare = 48 - charge_total = 96 - chaff_charge_size = 1 - flare_charge_size = 1 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - livery_name = "VSN_F4B" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 2, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (2, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 2, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - Mk_84___2000lb_GP_Bomb_LD = (2, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 2, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 2, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - BIN_200 = (2, Weapons.BIN_200) - VSN_F4EL_PTB = (2, Weapons.VSN_F4EL_PTB) - - class Pylon3: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (3, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 3, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_105_2_AIM_9L = (3, Weapons.LAU_105_2_AIM_9L) - LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM = ( - 3, - Weapons.LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9P5 = (3, Weapons.LAU_105_2_AIM_9P5) - LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM = ( - 3, - Weapons.LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9J = (3, Weapons.LAU_105_2_AIM_9J) - LAU_105_2_AIM_9JULI = (3, Weapons.LAU_105_2_AIM_9JULI) - AIM_7F_Sparrow_Semi_Active_Radar = (3, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 3, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BIN_200 = (3, Weapons.BIN_200) - F4B_LAU105_AIM9J_2_BRU42A_M117_3 = (3, Weapons.F4B_LAU105_AIM9J_2_BRU42A_M117_3) - F4B_LAU105_AIM9J_2_BRU42A_MK82_3 = (3, Weapons.F4B_LAU105_AIM9J_2_BRU42A_MK82_3) - F4B_LAU105_AIM9J_2_TER9A_MK82SE_3 = ( - 3, - Weapons.F4B_LAU105_AIM9J_2_TER9A_MK82SE_3, - ) - F4B_LAU105_AIM9J_2_MER_MK20_3 = (3, Weapons.F4B_LAU105_AIM9J_2_MER_MK20_3) - - class Pylon4: - AIM_7F_Sparrow_Semi_Active_Radar = (4, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 4, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon5: - AIM_7F_Sparrow_Semi_Active_Radar = (5, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon6: - Smokewinder___red = (6, Weapons.Smokewinder___red) - Smokewinder___green = (6, Weapons.Smokewinder___green) - Smokewinder___blue = (6, Weapons.Smokewinder___blue) - Smokewinder___white = (6, Weapons.Smokewinder___white) - Smokewinder___yellow = (6, Weapons.Smokewinder___yellow) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 6, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 6, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - ALQ_131___ECM_Pod = (6, Weapons.ALQ_131___ECM_Pod) - F4B_Gunpod_w_SAPHEI_T = (6, Weapons.F4B_Gunpod_w_SAPHEI_T) - VSN_F4EC_PTB = (6, Weapons.VSN_F4EC_PTB) - VSN_F4B_C2_PTB = (6, Weapons.VSN_F4B_C2_PTB) - - class Pylon7: - AIM_7F_Sparrow_Semi_Active_Radar = (7, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon8: - AIM_7F_Sparrow_Semi_Active_Radar = (8, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon9: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 9, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (9, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 9, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 9, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - Mk_84___2000lb_GP_Bomb_LD = (9, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 9, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 9, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 9, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 9, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_105_2_AIM_9L = (9, Weapons.LAU_105_2_AIM_9L) - LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM = ( - 9, - Weapons.LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9P5 = (9, Weapons.LAU_105_2_AIM_9P5) - LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM = ( - 9, - Weapons.LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9J = (9, Weapons.LAU_105_2_AIM_9J) - LAU_105_2_AIM_9JULI = (9, Weapons.LAU_105_2_AIM_9JULI) - AIM_7F_Sparrow_Semi_Active_Radar = (9, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 9, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 9, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 9, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 9, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BIN_200 = (9, Weapons.BIN_200) - F4B_LAU105_AIM9J_2_BRU42A_M117_3 = (9, Weapons.F4B_LAU105_AIM9J_2_BRU42A_M117_3) - F4B_LAU105_AIM9J_2_BRU42A_MK82_3 = (9, Weapons.F4B_LAU105_AIM9J_2_BRU42A_MK82_3) - F4B_LAU105_AIM9J_2_TER9A_MK82SE_3 = ( - 9, - Weapons.F4B_LAU105_AIM9J_2_TER9A_MK82SE_3, - ) - F4B_LAU105_AIM9J_2_MER_MK20_3 = (9, Weapons.F4B_LAU105_AIM9J_2_MER_MK20_3) - - class Pylon10: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 10, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = ( - 10, - Weapons.GBU_12___500lb_Laser_Guided_Bomb, - ) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 10, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - Mk_84___2000lb_GP_Bomb_LD = (10, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 10, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 10, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 10, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 10, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 10, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - BIN_200 = (10, Weapons.BIN_200) - VSN_F4ER_PTB = (10, Weapons.VSN_F4ER_PTB) - - class Pylon11: - # all added manually - did not pull using database export - BRU42A_M117_3_LAU105_AIM9J_2 = (11, Weapons.BRU_42A_M117_3_LAU105_AIM9J_2) - BRU42A_MK82_3_LAU105_AIM9J_2 = (11, Weapons.BRU_42A_MK82_3_LAU105_AIM9J_2) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 11, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 11, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - - class Pylon12: - # all added manually - did not pull using database export - BRU42A_M117_3_LAU105_AIM9J_2 = (12, Weapons.BRU_42A_M117_3_LAU105_AIM9J_2) - BRU42A_MK82_3_LAU105_AIM9J_2 = (12, Weapons.BRU_42A_MK82_3_LAU105_AIM9J_2) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 12, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 12, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.AFAC, - task.RunwayAttack, - ] - task_default = task.CAP - - -@planemod -class VSN_F4C(PlaneType): - id = "VSN_F4C" - flyable = True - height = 5.02 - width = 11.71 - length = 19.2 - fuel_max = 6416 - max_speed = 2545.2 - chaff = 48 - flare = 48 - charge_total = 96 - chaff_charge_size = 1 - flare_charge_size = 1 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - livery_name = "VSN_F4C" # from type - - class Pylon1: - Smoke_Generator___red_ = (1, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (1, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (1, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (1, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (1, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (1, Weapons.Smoke_Generator___orange_) - - class Pylon2: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 2, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (2, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 2, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - Mk_84___2000lb_GP_Bomb_LD = (2, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 2, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 2, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - BIN_200 = (2, Weapons.BIN_200) - VSN_F4EL_PTB = (2, Weapons.VSN_F4EL_PTB) - - class Pylon3: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (3, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 3, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD) - AGM_45B_Shrike_ARM__Imp_ = (3, Weapons.AGM_45B_Shrike_ARM__Imp_) - AGM_45A_Shrike_ARM = (3, Weapons.AGM_45A_Shrike_ARM) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_105_2_AIM_9L = (3, Weapons.LAU_105_2_AIM_9L) - LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM = ( - 3, - Weapons.LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9P5 = (3, Weapons.LAU_105_2_AIM_9P5) - LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM = ( - 3, - Weapons.LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9J = (3, Weapons.LAU_105_2_AIM_9J) - LAU_105_2_AIM_9JULI = (3, Weapons.LAU_105_2_AIM_9JULI) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 3, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BIN_200 = (3, Weapons.BIN_200) - - class Pylon4: - AIM_7F_Sparrow_Semi_Active_Radar = (4, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 4, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon5: - AIM_7F_Sparrow_Semi_Active_Radar = (5, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon6: - Smokewinder___red = (6, Weapons.Smokewinder___red) - Smokewinder___green = (6, Weapons.Smokewinder___green) - Smokewinder___blue = (6, Weapons.Smokewinder___blue) - Smokewinder___white = (6, Weapons.Smokewinder___white) - Smokewinder___yellow = (6, Weapons.Smokewinder___yellow) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 6, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 6, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - ALQ_131___ECM_Pod = (6, Weapons.ALQ_131___ECM_Pod) - F4B_Gunpod_w_SAPHEI_T = (6, Weapons.F4B_Gunpod_w_SAPHEI_T) - VSN_F4EC_PTB = (6, Weapons.VSN_F4EC_PTB) - VSN_F4B_C2_PTB = (6, Weapons.VSN_F4B_C2_PTB) - - class Pylon7: - AIM_7F_Sparrow_Semi_Active_Radar = (7, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon8: - AIM_7F_Sparrow_Semi_Active_Radar = (8, Weapons.AIM_7F_Sparrow_Semi_Active_Radar) - AIM_7E_2_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.AIM_7E_2_Sparrow_Semi_Active_Radar, - ) - - class Pylon9: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 9, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = (9, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 9, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD = ( - 9, - Weapons.BRU_42_with_3_x_Mk_82___500lb_GP_Bombs_LD, - ) - Mk_84___2000lb_GP_Bomb_LD = (9, Weapons.Mk_84___2000lb_GP_Bomb_LD) - AGM_45B_Shrike_ARM__Imp_ = (9, Weapons.AGM_45B_Shrike_ARM__Imp_) - AGM_45A_Shrike_ARM = (9, Weapons.AGM_45A_Shrike_ARM) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 9, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 9, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 9, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 9, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_105_2_AIM_9L = (9, Weapons.LAU_105_2_AIM_9L) - LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM = ( - 9, - Weapons.LAU_105_with_2_x_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9P5 = (9, Weapons.LAU_105_2_AIM_9P5) - LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM = ( - 9, - Weapons.LAU_7_with_2_x_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_105_2_AIM_9J = (9, Weapons.LAU_105_2_AIM_9J) - LAU_105_2_AIM_9JULI = (9, Weapons.LAU_105_2_AIM_9JULI) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 9, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - Mk_82___500lb_GP_Bomb_LD = (9, Weapons.Mk_82___500lb_GP_Bomb_LD) - TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 9, - Weapons.TER_9A_with_3_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 9, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BIN_200 = (9, Weapons.BIN_200) - - class Pylon10: - GBU_10___2000lb_Laser_Guided_Bomb = ( - 10, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_12___500lb_Laser_Guided_Bomb = ( - 10, - Weapons.GBU_12___500lb_Laser_Guided_Bomb, - ) - BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets = ( - 10, - Weapons.BRU_42_with_3_x_Mk_20_Rockeye___490lbs_CBUs__247_x_HEAT_Bomblets, - ) - Mk_84___2000lb_GP_Bomb_LD = (10, Weapons.Mk_84___2000lb_GP_Bomb_LD) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 10, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - _3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons._3_x_LAU_61_pods___57_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 10, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - Smokewinder___red = (10, Weapons.Smokewinder___red) - Smokewinder___green = (10, Weapons.Smokewinder___green) - Smokewinder___blue = (10, Weapons.Smokewinder___blue) - Smokewinder___white = (10, Weapons.Smokewinder___white) - Smokewinder___yellow = (10, Weapons.Smokewinder___yellow) - BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 10, - Weapons.BRU_33_with_2_x_LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 10, - Weapons.BRU_33_with_2_x_LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD = ( - 10, - Weapons.BRU_41A_with_6_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 10, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - BIN_200 = (10, Weapons.BIN_200) - VSN_F4ER_PTB = (10, Weapons.VSN_F4ER_PTB) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.Reconnaissance, - task.GroundAttack, - task.CAS, - task.AFAC, - task.RunwayAttack, - ] - task_default = task.CAP diff --git a/pydcs_extensions/fa18efg/__init__.py b/pydcs_extensions/fa18efg/__init__.py deleted file mode 100644 index 413f3c0f1..000000000 --- a/pydcs_extensions/fa18efg/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .fa18efg import * diff --git a/pydcs_extensions/fa18efg/fa18efg.py b/pydcs_extensions/fa18efg/fa18efg.py deleted file mode 100644 index 85039daec..000000000 --- a/pydcs_extensions/fa18efg/fa18efg.py +++ /dev/null @@ -1,2499 +0,0 @@ -from typing import Dict, List, Set, Any - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons -from dcs.unitpropertydescription import UnitPropertyDescription - - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsFA18EFG: - AA42R_Buddy_Pod = {"clsid": "{AA42R}", "name": "AA42R Buddy Pod", "weight": 1520} - ALQ_99Center = {"clsid": "{ALQ-99Center}", "name": "ALQ-99Center", "weight": 0} - ALQ_99Wing = {"clsid": "{ALQ-99Wing}", "name": "ALQ-99Wing", "weight": 0} - FLIR = {"clsid": "{FLIR}", "name": "FLIR", "weight": 0} - FPU_12_Fuel_Tank_480_gallons = { - "clsid": "{FPU_12_FUEL_TANK}", - "name": "FPU-12 Fuel Tank 480 gallons", - "weight": 1550, - } - FPU_12_Fuel_Tank_480_gallons_High_Vis = { - "clsid": "{FPU_12_FUEL_TANKHighVis}", - "name": "FPU-12 Fuel Tank 480 gallons High Vis", - "weight": 1550, - } - TLAU_127 = {"clsid": "{TLAU_127}", "name": "TLAU_127", "weight": 0} - USAFlag = {"clsid": "{USAFlag}", "name": "USAFlag", "weight": 0} - AIM_120D_AMRAAM___Active_Rdr_AAM = { - "clsid": "{C8E06185-7CD6-4C90-959F-044679E90751}", - "name": "AIM-120D AMRAAM - Active Rdr AAM", - "weight": 162.4, - } - LAU_115_2_LAU_127_AIM_120B = { - "clsid": "LAU-115_2*LAU-127_AIM-120B", - "name": "LAU-115 with 2 x LAU-127 AIM-120D AMRAAM - Active Rdr AAM", - "weight": 469.8, - } - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM = { - "clsid": "{LAU-115 - AIM-120B}", - "name": "LAU-115 with 1 x LAU-127 AIM-120D AMRAAM - Active Rdr AAM", - "weight": 307.4, - } - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM_ = { - "clsid": "{LAU-115 - AIM-120B_R}", - "name": "LAU-115 with 1 x LAU-127 AIM-120D AMRAAM - Active Rdr AAM", - "weight": 307.4, - } - - -inject_weapons(WeaponsFA18EFG) - - -@planemod -class FA_18E(PlaneType): - id = "FA-18E" - flyable = True - height = 4.88 - width = 13.62456 - length = 18.31 - fuel_max = 4900 - max_speed = 2120.04 - chaff = 60 - flare = 60 - charge_total = 120 - chaff_charge_size = 1 - flare_charge_size = 1 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 305 - - panel_radio = { - 1: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - 2: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - } - - callnames: Dict[str, List[str]] = { - "USA": [ - "Hornet", - "Squid", - "Ragin", - "Roman", - "Sting", - "Jury", - "Joker", - "Ram", - "Hawk", - "Devil", - "Check", - "Snake", - ] - } - - property_defaults: Dict[str, Any] = { - "OuterBoard": 0, - "InnerBoard": 0, - "HelmetMountedDevice": 1, - "VoiceCallsignLabel": None, - "VoiceCallsignNumber": None, - "STN_L16": None, - } - - class Properties: - class OuterBoard: - id = "OuterBoard" - - class Values: - Single = 0 - Ripple = 1 - - class InnerBoard: - id = "InnerBoard" - - class Values: - Single = 0 - Ripple = 1 - - class HelmetMountedDevice: - id = "HelmetMountedDevice" - - class Values: - Not_installed = 0 - JHMCS = 1 - NVG = 2 - - class VoiceCallsignLabel: - id = "VoiceCallsignLabel" - - class VoiceCallsignNumber: - id = "VoiceCallsignNumber" - - class STN_L16: - id = "STN_L16" - - properties = { - "OuterBoard": UnitPropertyDescription( - identifier="OuterBoard", - control="comboList", - label="Outerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "InnerBoard": UnitPropertyDescription( - identifier="InnerBoard", - control="comboList", - label="Innerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "HelmetMountedDevice": UnitPropertyDescription( - identifier="HelmetMountedDevice", - control="comboList", - label="Helmet Mounted Device", - player_only=True, - default=1, - w_ctrl=150, - values={ - 0: "Not installed", - 1: "JHMCS", - 2: "NVG", - }, - ), - "datalink_Label": UnitPropertyDescription( - identifier="datalink_Label", - control="label", - label="DATALINK", - player_only=False, - x_lbl=150, - ), - "VoiceCallsignLabel": UnitPropertyDescription( - identifier="VoiceCallsignLabel", - control="editbox", - label="Voice Callsign Label", - player_only=False, - ), - "VoiceCallsignNumber": UnitPropertyDescription( - identifier="VoiceCallsignNumber", - control="editbox", - label="Voice Callsign Number", - player_only=False, - ), - "STN_L16": UnitPropertyDescription( - identifier="STN_L16", - control="editbox", - label="STN", - player_only=False, - ), - } - - livery_name = "FA-18E" # from type - - class Pylon1: - AIM_9M_Sidewinder_IR_AAM = (1, Weapons.AIM_9M_Sidewinder_IR_AAM) - CATM_9M = (1, Weapons.CATM_9M) - # ERRR {CATM-9M} - # ERRR {CATM-9X} - AIM_9X_Sidewinder_IR_AAM = (1, Weapons.AIM_9X_Sidewinder_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - - class Pylon2: - TLAU_127 = (2, Weapons.TLAU_127) - AIM_120D_AMRAAM___Active_Rdr_AAM = (2, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 2, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - # ERRR {CATM-120C} - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 2, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_AGM_65F = (2, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 2, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (2, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 2, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (2, Weapons.Mk_83___1000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (2, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (2, Weapons.BDU_45B___500lb_Practice_Bomb) - GBU_12___500lb_Laser_Guided_Bomb = (2, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 2, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 2, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 2, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - # ERRR - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 2, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 2, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 2, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_2_x_ADM_141A_TALD = (2, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (2, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon3: - LAU_115_2_LAU_127_AIM_9M = (3, Weapons.LAU_115_2_LAU_127_AIM_9M) - LAU_115_2_LAU_127_CATM_9M = (3, Weapons.LAU_115_2_LAU_127_CATM_9M) - LAU_115_2_LAU_127_AIM_9L = (3, Weapons.LAU_115_2_LAU_127_AIM_9L) - LAU_115_2_LAU_127_AIM_9X = (3, Weapons.LAU_115_2_LAU_127_AIM_9X) - LAU_115_LAU_127_AIM_9X = (3, Weapons.LAU_115_LAU_127_AIM_9X) - LAU_115_LAU_127_CATM_9M = (3, Weapons.LAU_115_LAU_127_CATM_9M) - LAU_115_LAU_127_AIM_9L = (3, Weapons.LAU_115_LAU_127_AIM_9L) - LAU_115_LAU_127_AIM_9M = (3, Weapons.LAU_115_LAU_127_AIM_9M) - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (3, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 3, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - AIM_120D_AMRAAM___Active_Rdr_AAM = (3, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 3, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (3, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (3, Weapons.LAU_115_2_LAU_127_AIM_120C) - # ERRR LAU-115_2*LAU-127_CATM-120C - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 3, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (3, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (3, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 3, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (3, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 3, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (3, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (3, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (3, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 3, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 3, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 3, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 3, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (3, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 3, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (3, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 3, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (3, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 3, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 3, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 3, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (3, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (3, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 3, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_3_x_ADM_141A_TALD = (3, Weapons.BRU_42_with_3_x_ADM_141A_TALD) - BRU_42_with_2_x_ADM_141A_TALD = (3, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (3, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon4: - AIM_120D_AMRAAM___Active_Rdr_AAM = (4, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 4, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - AN_ASQ_228_ATFLIR___Targeting_Pod = ( - 4, - Weapons.AN_ASQ_228_ATFLIR___Targeting_Pod, - ) - - class Pylon5: - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (5, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 5, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM = ( - 5, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM, - ) - LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM = ( - 5, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (5, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (5, Weapons.LAU_115_2_LAU_127_AIM_120C) - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 5, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (5, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (5, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 5, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (5, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 5, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (5, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (5, Weapons.Mk_84___2000lb_GP_Bomb_LD) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 5, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 5, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 5, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 5, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 5, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (5, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 5, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 5, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 5, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 5, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (5, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 5, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (5, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 5, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 5, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 5, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (5, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (5, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 5, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - - class Pylon6: - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (6, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 6, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM = ( - 6, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM, - ) - LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM = ( - 6, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (6, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (6, Weapons.LAU_115_2_LAU_127_AIM_120C) - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 6, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (6, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (6, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 6, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 6, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (6, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (6, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (6, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 6, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 6, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 6, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (6, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 6, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 6, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 6, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (6, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 6, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (6, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 6, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 6, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 6, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (6, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (6, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 6, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - - class Pylon7: - LAU_115_2_LAU_127_AIM_9M = (7, Weapons.LAU_115_2_LAU_127_AIM_9M) - LAU_115_2_LAU_127_CATM_9M = (7, Weapons.LAU_115_2_LAU_127_CATM_9M) - LAU_115_2_LAU_127_AIM_9L = (7, Weapons.LAU_115_2_LAU_127_AIM_9L) - LAU_115_2_LAU_127_AIM_9X = (7, Weapons.LAU_115_2_LAU_127_AIM_9X) - LAU_115_LAU_127_AIM_9X = (7, Weapons.LAU_115_LAU_127_AIM_9X) - LAU_115_LAU_127_CATM_9M = (7, Weapons.LAU_115_LAU_127_CATM_9M) - LAU_115_LAU_127_AIM_9L = (7, Weapons.LAU_115_LAU_127_AIM_9L) - LAU_115_LAU_127_AIM_9M = (7, Weapons.LAU_115_LAU_127_AIM_9M) - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (7, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 7, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - AIM_120D_AMRAAM___Active_Rdr_AAM = (7, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 7, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (7, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (7, Weapons.LAU_115_2_LAU_127_AIM_120C) - # ERRR LAU-115_2*LAU-127_CATM-120C - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 7, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (7, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (7, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 7, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (7, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (7, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 7, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (7, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (7, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (7, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (7, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 7, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 7, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 7, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 7, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 7, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (7, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 7, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 7, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 7, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (7, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 7, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (7, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 7, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 7, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 7, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (7, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (7, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 7, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_3_x_ADM_141A_TALD = (7, Weapons.BRU_42_with_3_x_ADM_141A_TALD) - BRU_42_with_2_x_ADM_141A_TALD = (7, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (7, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon8: - TLAU_127 = (8, Weapons.TLAU_127) - AIM_120D_AMRAAM___Active_Rdr_AAM = (8, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 8, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - # ERRR {CATM-120C} - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 8, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_AGM_65F = (8, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 8, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (8, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 8, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (8, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (8, Weapons.BDU_45B___500lb_Practice_Bomb) - GBU_12___500lb_Laser_Guided_Bomb = (8, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 8, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 8, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - # ERRR - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 8, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 8, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 8, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_2_x_ADM_141A_TALD = (8, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (8, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon9: - AIM_9M_Sidewinder_IR_AAM = (9, Weapons.AIM_9M_Sidewinder_IR_AAM) - CATM_9M = (9, Weapons.CATM_9M) - # ERRR {CATM-9M} - # ERRR {CATM-9X} - AIM_9X_Sidewinder_IR_AAM = (9, Weapons.AIM_9X_Sidewinder_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (9, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - - # ERRR - - class Pylon10: - AA42R_Buddy_Pod = (10, Weapons.AA42R_Buddy_Pod) - FPU_12_Fuel_Tank_480_gallons = (10, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 10, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - USAFlag = (10, Weapons.USAFlag) - Smoke_Generator___red_ = (10, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (10, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (10, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (10, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (10, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (10, Weapons.Smoke_Generator___orange_) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.PinpointStrike, - task.CAS, - task.GroundAttack, - task.RunwayAttack, - task.SEAD, - task.AFAC, - task.AntishipStrike, - task.Reconnaissance, - ] - task_default = task.CAP - - -from typing import Dict, List, Any - - -@planemod -class FA_18F(PlaneType): - id = "FA-18F" - flyable = True - height = 4.88 - width = 13.62456 - length = 18.31 - fuel_max = 4900 - max_speed = 2120.04 - chaff = 60 - flare = 60 - charge_total = 120 - chaff_charge_size = 1 - flare_charge_size = 1 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 305 - - panel_radio = { - 1: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - 2: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - } - - callnames: Dict[str, List[str]] = { - "USA": [ - "Hornet", - "Squid", - "Ragin", - "Roman", - "Sting", - "Jury", - "Joker", - "Ram", - "Hawk", - "Devil", - "Check", - "Snake", - ] - } - - property_defaults: Dict[str, Any] = { - "OuterBoard": 0, - "InnerBoard": 0, - "HelmetMountedDevice": 1, - "VoiceCallsignLabel": None, - "VoiceCallsignNumber": None, - "STN_L16": None, - } - - class Properties: - class OuterBoard: - id = "OuterBoard" - - class Values: - Single = 0 - Ripple = 1 - - class InnerBoard: - id = "InnerBoard" - - class Values: - Single = 0 - Ripple = 1 - - class HelmetMountedDevice: - id = "HelmetMountedDevice" - - class Values: - Not_installed = 0 - JHMCS = 1 - NVG = 2 - - class VoiceCallsignLabel: - id = "VoiceCallsignLabel" - - class VoiceCallsignNumber: - id = "VoiceCallsignNumber" - - class STN_L16: - id = "STN_L16" - - properties = { - "OuterBoard": UnitPropertyDescription( - identifier="OuterBoard", - control="comboList", - label="Outerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "InnerBoard": UnitPropertyDescription( - identifier="InnerBoard", - control="comboList", - label="Innerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "HelmetMountedDevice": UnitPropertyDescription( - identifier="HelmetMountedDevice", - control="comboList", - label="Helmet Mounted Device", - player_only=True, - default=1, - w_ctrl=150, - values={ - 0: "Not installed", - 1: "JHMCS", - 2: "NVG", - }, - ), - "datalink_Label": UnitPropertyDescription( - identifier="datalink_Label", - control="label", - label="DATALINK", - player_only=False, - x_lbl=150, - ), - "VoiceCallsignLabel": UnitPropertyDescription( - identifier="VoiceCallsignLabel", - control="editbox", - label="Voice Callsign Label", - player_only=False, - ), - "VoiceCallsignNumber": UnitPropertyDescription( - identifier="VoiceCallsignNumber", - control="editbox", - label="Voice Callsign Number", - player_only=False, - ), - "STN_L16": UnitPropertyDescription( - identifier="STN_L16", - control="editbox", - label="STN", - player_only=False, - ), - } - - livery_name = "FA-18F" # from type - - class Pylon1: - AIM_9M_Sidewinder_IR_AAM = (1, Weapons.AIM_9M_Sidewinder_IR_AAM) - CATM_9M = (1, Weapons.CATM_9M) - # ERRR {CATM-9M} - # ERRR {CATM-9X} - AIM_9X_Sidewinder_IR_AAM = (1, Weapons.AIM_9X_Sidewinder_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - - class Pylon2: - TLAU_127 = (2, Weapons.TLAU_127) - AIM_120D_AMRAAM___Active_Rdr_AAM = (2, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 2, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - # ERRR {CATM-120C} - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 2, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 2, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_AGM_65F = (2, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 2, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (2, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 2, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (2, Weapons.Mk_83___1000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (2, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (2, Weapons.BDU_45B___500lb_Practice_Bomb) - GBU_12___500lb_Laser_Guided_Bomb = (2, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 2, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 2, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 2, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - # ERRR - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 2, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 2, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 2, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_2_x_ADM_141A_TALD = (2, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (2, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon3: - LAU_115_2_LAU_127_AIM_9M = (3, Weapons.LAU_115_2_LAU_127_AIM_9M) - LAU_115_2_LAU_127_CATM_9M = (3, Weapons.LAU_115_2_LAU_127_CATM_9M) - LAU_115_2_LAU_127_AIM_9L = (3, Weapons.LAU_115_2_LAU_127_AIM_9L) - LAU_115_2_LAU_127_AIM_9X = (3, Weapons.LAU_115_2_LAU_127_AIM_9X) - LAU_115_LAU_127_AIM_9X = (3, Weapons.LAU_115_LAU_127_AIM_9X) - LAU_115_LAU_127_CATM_9M = (3, Weapons.LAU_115_LAU_127_CATM_9M) - LAU_115_LAU_127_AIM_9L = (3, Weapons.LAU_115_LAU_127_AIM_9L) - LAU_115_LAU_127_AIM_9M = (3, Weapons.LAU_115_LAU_127_AIM_9M) - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 3, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (3, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 3, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - AIM_120D_AMRAAM___Active_Rdr_AAM = (3, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 3, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (3, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (3, Weapons.LAU_115_2_LAU_127_AIM_120C) - # ERRR LAU-115_2*LAU-127_CATM-120C - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 3, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (3, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (3, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 3, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (3, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 3, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (3, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (3, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (3, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (3, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 3, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 3, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 3, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 3, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 3, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (3, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 3, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 3, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 3, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 3, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 3, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (3, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 3, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (3, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 3, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 3, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 3, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 3, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (3, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (3, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 3, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_3_x_ADM_141A_TALD = (3, Weapons.BRU_42_with_3_x_ADM_141A_TALD) - BRU_42_with_2_x_ADM_141A_TALD = (3, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (3, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon4: - AIM_120D_AMRAAM___Active_Rdr_AAM = (4, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 4, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - AN_ASQ_228_ATFLIR___Targeting_Pod = ( - 4, - Weapons.AN_ASQ_228_ATFLIR___Targeting_Pod, - ) - - class Pylon5: - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 5, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (5, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 5, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM = ( - 5, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM, - ) - LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM = ( - 5, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (5, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (5, Weapons.LAU_115_2_LAU_127_AIM_120C) - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 5, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (5, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (5, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 5, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (5, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 5, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (5, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (5, Weapons.Mk_84___2000lb_GP_Bomb_LD) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 5, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 5, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 5, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 5, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 5, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 5, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (5, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 5, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 5, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 5, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 5, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 5, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (5, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 5, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (5, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 5, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 5, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 5, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 5, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (5, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (5, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 5, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - - class Pylon6: - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 6, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (6, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 6, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM = ( - 6, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120D_AMRAAM___Active_Rdr_AAM, - ) - LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM = ( - 6, - Weapons.LAU_115_with_1_x_LAU_127_AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (6, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (6, Weapons.LAU_115_2_LAU_127_AIM_120C) - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 6, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (6, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (6, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 6, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 6, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (6, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (6, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (6, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 6, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 6, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 6, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 6, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 6, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (6, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 6, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 6, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 6, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 6, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 6, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (6, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 6, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (6, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 6, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 6, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 6, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 6, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (6, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (6, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 6, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - - class Pylon7: - LAU_115_2_LAU_127_AIM_9M = (7, Weapons.LAU_115_2_LAU_127_AIM_9M) - LAU_115_2_LAU_127_CATM_9M = (7, Weapons.LAU_115_2_LAU_127_CATM_9M) - LAU_115_2_LAU_127_AIM_9L = (7, Weapons.LAU_115_2_LAU_127_AIM_9L) - LAU_115_2_LAU_127_AIM_9X = (7, Weapons.LAU_115_2_LAU_127_AIM_9X) - LAU_115_LAU_127_AIM_9X = (7, Weapons.LAU_115_LAU_127_AIM_9X) - LAU_115_LAU_127_CATM_9M = (7, Weapons.LAU_115_LAU_127_CATM_9M) - LAU_115_LAU_127_AIM_9L = (7, Weapons.LAU_115_LAU_127_AIM_9L) - LAU_115_LAU_127_AIM_9M = (7, Weapons.LAU_115_LAU_127_AIM_9M) - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 7, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - FPU_12_Fuel_Tank_480_gallons = (7, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 7, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - AIM_120D_AMRAAM___Active_Rdr_AAM = (7, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 7, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - LAU_115_2_LAU_127_AIM_120B = (7, Weapons.LAU_115_2_LAU_127_AIM_120B) - LAU_115_2_LAU_127_AIM_120C = (7, Weapons.LAU_115_2_LAU_127_AIM_120C) - # ERRR LAU-115_2*LAU-127_CATM-120C - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 7, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_CATM_65K = (7, Weapons.LAU_117_CATM_65K) - LAU_117_AGM_65F = (7, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 7, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (7, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (7, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 7, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (7, Weapons.Mk_83___1000lb_GP_Bomb_LD) - Mk_84___2000lb_GP_Bomb_LD = (7, Weapons.Mk_84___2000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (7, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (7, Weapons.BDU_45B___500lb_Practice_Bomb) - AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_ = ( - 7, - Weapons.AGM_84E_Harpoon_SLAM__Stand_Off_Land_Attack_Missile_, - ) - AGM_84H_SLAM_ER__Expanded_Response_ = ( - 7, - Weapons.AGM_84H_SLAM_ER__Expanded_Response_, - ) - BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82___500lb_GP_Bomb_LD, - ) - BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82_Snakeye___500lb_GP_Bomb_HD, - ) - BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_BDU_45___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_BDU_45B___500lb_Practice_Bomb, - ) - BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 7, - Weapons.BRU_33_with_2_x_Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD = ( - 7, - Weapons.BRU_33_with_2_x_Mk_83___1000lb_GP_Bomb_LD, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 7, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_10___2000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_10___2000lb_Laser_Guided_Bomb, - ) - BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD = ( - 7, - Weapons.BRU_41A_with_6_x_BDU_33___25lb_Practice_Bomb_LD, - ) - GBU_12___500lb_Laser_Guided_Bomb = (7, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_24A_B_Paveway_III___2000lb_Laser_Guided_Bomb, - ) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 7, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 7, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 7, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 7, - Weapons.BRU_33_with_2_x_CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb = ( - 7, - Weapons.BRU_33_with_2_x_GBU_12___500lb_Laser_Guided_Bomb, - ) - # ERRR - AGM_154A___JSOW_CEB__CBU_type_ = (7, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 7, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (7, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 7, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_31_V_2_B___JDAM__2000lb_GPS_Guided_Bomb, - ) - GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb = ( - 7, - Weapons.GBU_31_V_4_B___JDAM__2000lb_GPS_Guided_Penetrator_Bomb, - ) - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 7, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb = ( - 7, - Weapons.BRU_55_with_2_x_GBU_38___JDAM__500lb_GPS_Guided_Bomb, - ) - AGM_84D_Harpoon_AShM = (7, Weapons.AGM_84D_Harpoon_AShM) - AWW_13_DATALINK_POD = (7, Weapons.AWW_13_DATALINK_POD) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 7, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_3_x_ADM_141A_TALD = (7, Weapons.BRU_42_with_3_x_ADM_141A_TALD) - BRU_42_with_2_x_ADM_141A_TALD = (7, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (7, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon8: - TLAU_127 = (8, Weapons.TLAU_127) - AIM_120D_AMRAAM___Active_Rdr_AAM = (8, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 8, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - # ERRR {CATM-120C} - LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7M_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7F_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7MH_Sparrow_Semi_Active_Radar, - ) - LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar = ( - 8, - Weapons.LAU_115C_with_AIM_7P_Sparrow_Semi_Active_Radar, - ) - # ERRR LAU_117_TGM_65E - # ERRR LAU_117_TGM_65F - LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_ = ( - 8, - Weapons.LAU_117_with_AGM_65E___Maverick_E__Laser_ASM___Lg_Whd_, - ) - LAU_117_AGM_65F = (8, Weapons.LAU_117_AGM_65F) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 8, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - Mk_82___500lb_GP_Bomb_LD = (8, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (8, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_82Y___500lb_GP_Chute_Retarded_HD = ( - 8, - Weapons.Mk_82Y___500lb_GP_Chute_Retarded_HD, - ) - Mk_83___1000lb_GP_Bomb_LD = (8, Weapons.Mk_83___1000lb_GP_Bomb_LD) - BDU_45___500lb_Practice_Bomb = (8, Weapons.BDU_45___500lb_Practice_Bomb) - BDU_45B___500lb_Practice_Bomb = (8, Weapons.BDU_45B___500lb_Practice_Bomb) - GBU_12___500lb_Laser_Guided_Bomb = (8, Weapons.GBU_12___500lb_Laser_Guided_Bomb) - GBU_16___1000lb_Laser_Guided_Bomb = ( - 8, - Weapons.GBU_16___1000lb_Laser_Guided_Bomb, - ) - CBU_99___490lbs__247_x_HEAT_Bomblets = ( - 8, - Weapons.CBU_99___490lbs__247_x_HEAT_Bomblets, - ) - Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets = ( - 8, - Weapons.Mk_20_Rockeye___490lbs_CBU__247_x_HEAT_Bomblets, - ) - # ERRR - GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb = ( - 8, - Weapons.GBU_32_V_2_B___JDAM__1000lb_GPS_Guided_Bomb, - ) - GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb = ( - 8, - Weapons.GBU_38_V_1_B___JDAM__500lb_GPS_Guided_Bomb, - ) - GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD = ( - 8, - Weapons.GBU_54_V_1_B___LJDAM__500lb_Laser__GPS_Guided_Bomb_LD, - ) - BRU_42_with_2_x_ADM_141A_TALD = (8, Weapons.BRU_42_with_2_x_ADM_141A_TALD) - BRU_42_with_ADM_141A_TALD = (8, Weapons.BRU_42_with_ADM_141A_TALD) - - class Pylon9: - AIM_9M_Sidewinder_IR_AAM = (9, Weapons.AIM_9M_Sidewinder_IR_AAM) - CATM_9M = (9, Weapons.CATM_9M) - # ERRR {CATM-9M} - # ERRR {CATM-9X} - AIM_9X_Sidewinder_IR_AAM = (9, Weapons.AIM_9X_Sidewinder_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (9, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - - # ERRR - - class Pylon10: - AA42R_Buddy_Pod = (10, Weapons.AA42R_Buddy_Pod) - FPU_12_Fuel_Tank_480_gallons = (10, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 10, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - USAFlag = (10, Weapons.USAFlag) - Smoke_Generator___red_ = (10, Weapons.Smoke_Generator___red_) - Smoke_Generator___green_ = (10, Weapons.Smoke_Generator___green_) - Smoke_Generator___blue_ = (10, Weapons.Smoke_Generator___blue_) - Smoke_Generator___white_ = (10, Weapons.Smoke_Generator___white_) - Smoke_Generator___yellow_ = (10, Weapons.Smoke_Generator___yellow_) - Smoke_Generator___orange_ = (10, Weapons.Smoke_Generator___orange_) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.PinpointStrike, - task.CAS, - task.GroundAttack, - task.RunwayAttack, - task.SEAD, - task.AFAC, - task.AntishipStrike, - task.Reconnaissance, - ] - task_default = task.CAP - - -@planemod -class EA_18G(PlaneType): - id = "EA-18G" - flyable = True - height = 4.88 - width = 13.62456 - length = 18.31 - fuel_max = 4900 - max_speed = 2120.04 - chaff = 60 - flare = 60 - charge_total = 120 - chaff_charge_size = 1 - flare_charge_size = 1 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 305 - - panel_radio = { - 1: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - 2: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 268, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - } - - callnames: Dict[str, List[str]] = { - "USA": [ - "Hornet", - "Squid", - "Ragin", - "Roman", - "Sting", - "Jury", - "Joker", - "Ram", - "Hawk", - "Devil", - "Check", - "Snake", - ] - } - - property_defaults: Dict[str, Any] = { - "OuterBoard": 0, - "InnerBoard": 0, - "HelmetMountedDevice": 1, - "VoiceCallsignLabel": None, - "VoiceCallsignNumber": None, - "STN_L16": None, - } - - class Properties: - class OuterBoard: - id = "OuterBoard" - - class Values: - Single = 0 - Ripple = 1 - - class InnerBoard: - id = "InnerBoard" - - class Values: - Single = 0 - Ripple = 1 - - class HelmetMountedDevice: - id = "HelmetMountedDevice" - - class Values: - Not_installed = 0 - JHMCS = 1 - NVG = 2 - - class VoiceCallsignLabel: - id = "VoiceCallsignLabel" - - class VoiceCallsignNumber: - id = "VoiceCallsignNumber" - - class STN_L16: - id = "STN_L16" - - properties = { - "OuterBoard": UnitPropertyDescription( - identifier="OuterBoard", - control="comboList", - label="Outerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "InnerBoard": UnitPropertyDescription( - identifier="InnerBoard", - control="comboList", - label="Innerboard rockets mode", - player_only=True, - default=0, - w_ctrl=150, - values={ - 0: "Single", - 1: "Ripple", - }, - ), - "HelmetMountedDevice": UnitPropertyDescription( - identifier="HelmetMountedDevice", - control="comboList", - label="Helmet Mounted Device", - player_only=True, - default=1, - w_ctrl=150, - values={ - 0: "Not installed", - 1: "JHMCS", - 2: "NVG", - }, - ), - "datalink_Label": UnitPropertyDescription( - identifier="datalink_Label", - control="label", - label="DATALINK", - player_only=False, - x_lbl=150, - ), - "VoiceCallsignLabel": UnitPropertyDescription( - identifier="VoiceCallsignLabel", - control="editbox", - label="Voice Callsign Label", - player_only=False, - ), - "VoiceCallsignNumber": UnitPropertyDescription( - identifier="VoiceCallsignNumber", - control="editbox", - label="Voice Callsign Number", - player_only=False, - ), - "STN_L16": UnitPropertyDescription( - identifier="STN_L16", - control="editbox", - label="STN", - player_only=False, - ), - } - - livery_name = "EA-18G" # from type - - class Pylon1: - FPU_12_Fuel_Tank_480_gallons = (1, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 1, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - ALQ_99Wing = (1, Weapons.ALQ_99Wing) - - # ERRR - - class Pylon2: - FPU_12_Fuel_Tank_480_gallons = (2, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 2, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - ALQ_99Wing = (2, Weapons.ALQ_99Wing) - AGM_154A___JSOW_CEB__CBU_type_ = (2, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 2, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (2, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 2, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 2, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - - # ERRR - - class Pylon3: - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (3, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 3, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - # ERRR - TLAU_127 = (3, Weapons.TLAU_127) - - class Pylon4: - AIM_120D_AMRAAM___Active_Rdr_AAM = (4, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 4, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - - class Pylon5: - FPU_12_Fuel_Tank_480_gallons = (5, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 5, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - ALQ_99Center = (5, Weapons.ALQ_99Center) - - # ERRR - - class Pylon6: - AIM_120D_AMRAAM___Active_Rdr_AAM = (6, Weapons.AIM_120D_AMRAAM___Active_Rdr_AAM) - AIM_120C_AMRAAM___Active_Radar_AAM = ( - 6, - Weapons.AIM_120C_AMRAAM___Active_Radar_AAM, - ) - - class Pylon7: - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (7, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 7, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - # ERRR - TLAU_127 = (7, Weapons.TLAU_127) - - class Pylon8: - FPU_12_Fuel_Tank_480_gallons = (8, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 8, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - ALQ_99Wing = (8, Weapons.ALQ_99Wing) - AGM_154A___JSOW_CEB__CBU_type_ = (8, Weapons.AGM_154A___JSOW_CEB__CBU_type_) - BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_ = ( - 8, - Weapons.BRU_55_with_2_x_AGM_154A___JSOW_CEB__CBU_type_, - ) - AGM_154C___JSOW_Unitary_BROACH = (8, Weapons.AGM_154C___JSOW_Unitary_BROACH) - BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH = ( - 8, - Weapons.BRU_55_with_2_x_AGM_154C___JSOW_Unitary_BROACH, - ) - AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_ = ( - 8, - Weapons.AGM_88C_HARM___High_Speed_Anti_Radiation_Missile_, - ) - - # ERRR - - class Pylon9: - FPU_12_Fuel_Tank_480_gallons = (9, Weapons.FPU_12_Fuel_Tank_480_gallons) - FPU_12_Fuel_Tank_480_gallons_High_Vis = ( - 9, - Weapons.FPU_12_Fuel_Tank_480_gallons_High_Vis, - ) - ALQ_99Wing = (9, Weapons.ALQ_99Wing) - - # ERRR - - class Pylon10: - USAFlag = (10, Weapons.USAFlag) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - - tasks = [ - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - task.PinpointStrike, - task.CAS, - task.GroundAttack, - task.RunwayAttack, - task.SEAD, - task.AFAC, - task.AntishipStrike, - task.Reconnaissance, - ] - task_default = task.CAP diff --git a/pydcs_extensions/frenchpack/__init__.py b/pydcs_extensions/frenchpack/__init__.py deleted file mode 100644 index 1a429b033..000000000 --- a/pydcs_extensions/frenchpack/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .frenchpack import * diff --git a/pydcs_extensions/frenchpack/frenchpack.py b/pydcs_extensions/frenchpack/frenchpack.py deleted file mode 100644 index eaad717d4..000000000 --- a/pydcs_extensions/frenchpack/frenchpack.py +++ /dev/null @@ -1,418 +0,0 @@ -# Requires French Pack mod : -# https://forums.eagle.ru/showthread.php?t=279974 -# -from dcs import unittype - -from game.modsupport import vehiclemod - - -@vehiclemod -class AMX_10RCR(unittype.VehicleType): - id = "AMX10RCR" - name = "AMX-10RCR" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class AMX_10RCR_SEPAR(unittype.VehicleType): - id = "SEPAR" - name = "AMX-10RCR SEPAR" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class ERC_90(unittype.VehicleType): - id = "ERC" - name = "ERC-90" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - eplrs = True - - -@vehiclemod -class VAB__50(unittype.VehicleType): - id = "VAB_50" - name = "VAB .50" - detection_range = 0 - threat_range = 1200 - air_weapon_dist = 1200 - eplrs = True - - -@vehiclemod -class VAB_T20_13(unittype.VehicleType): - id = "VIB_VBR" - name = "VAB T20/13" - detection_range = 0 - threat_range = 2000 - air_weapon_dist = 2000 - eplrs = True - - -@vehiclemod -class VAB_MEPHISTO(unittype.VehicleType): - id = "VAB_HOT" - name = "VAB MEPHISTO" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - eplrs = True - - -@vehiclemod -class VBL__50(unittype.VehicleType): - id = "VBL50" - name = "VBL .50" - detection_range = 0 - threat_range = 1200 - air_weapon_dist = 1200 - eplrs = True - - -@vehiclemod -class VBL_AANF1(unittype.VehicleType): - id = "VBLANF1" - name = "VBL AANF1" - detection_range = 0 - threat_range = 1000 - air_weapon_dist = 1000 - eplrs = True - - -@vehiclemod -class VBAE_CRAB(unittype.VehicleType): - id = "VBAE" - name = "VBAE CRAB" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 3500 - eplrs = True - - -@vehiclemod -class VBAE_CRAB_MMP(unittype.VehicleType): - id = "VBAE_MMP" - name = "VBAE CRAB MMP" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 3500 - eplrs = True - - -@vehiclemod -class AMX_30B2(unittype.VehicleType): - id = "AMX-30B2" - name = "AMX-30B2" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 2500 - - -@vehiclemod -class Char_M551_Sheridan(unittype.VehicleType): - id = "SHERIDAN" - name = "Char M551 Sheridan" - detection_range = 0 - threat_range = 5000 - air_weapon_dist = 5000 - - -@vehiclemod -class Leclerc_Serie_XXI(unittype.VehicleType): - id = "Leclerc_XXI" - name = "Leclerc Série XXI" - detection_range = 0 - threat_range = 5000 - air_weapon_dist = 5000 - - -@vehiclemod -class DIM__TOYOTA_BLUE(unittype.VehicleType): - id = "Toyota_bleu" - name = "DIM' TOYOTA BLUE" - detection_range = 0 - threat_range = 1200 - air_weapon_dist = 1200 - eplrs = True - - -@vehiclemod -class DIM__TOYOTA_GREEN(unittype.VehicleType): - id = "Toyota_vert" - name = "DIM' TOYOTA GREEN" - detection_range = 0 - threat_range = 1200 - air_weapon_dist = 1200 - eplrs = True - - -@vehiclemod -class DIM__TOYOTA_DESERT(unittype.VehicleType): - id = "Toyota_desert" - name = "DIM' TOYOTA DESERT" - detection_range = 0 - threat_range = 1200 - air_weapon_dist = 1200 - eplrs = True - - -@vehiclemod -class DIM__KAMIKAZE(unittype.VehicleType): - id = "Kamikaze" - name = "DIM' KAMIKAZE" - detection_range = 0 - threat_range = 50 - air_weapon_dist = 50 - eplrs = True - - -## FORTIFICATION - - -@vehiclemod -class _FIELD_HIDE(unittype.VehicleType): - id = "FieldHL" - name = "*FIELD HIDE" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class _FIELD_HIDE_SMALL(unittype.VehicleType): - id = "HARRIERH" - name = "*FIELD HIDE SMALL" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SmokeD1(unittype.VehicleType): - id = "SmokeD1" - name = "SmokeD1" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SmokeD3(unittype.VehicleType): - id = "SmokeD3" - name = "SmokeD3" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class TRM_2000(unittype.VehicleType): - id = "TRM2000" - name = "TRM-2000" - detection_range = 3500 - threat_range = 0 - air_weapon_dist = 0 - eplrs = True - - -@vehiclemod -class TRM_2000_Fuel(unittype.VehicleType): - id = "TRM2000_Citerne" - name = "TRM-2000 Fuel" - detection_range = 3500 - threat_range = 0 - air_weapon_dist = 0 - eplrs = True - - -@vehiclemod -class VAB_MEDICAL(unittype.VehicleType): - id = "VABH" - name = "VAB MEDICAL" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - eplrs = True - - -@vehiclemod -class VAB(unittype.VehicleType): - id = "VAB_RADIO" - name = "VAB" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - eplrs = True - - -@vehiclemod -class VBL(unittype.VehicleType): - id = "VBL-Radio" - name = "VBL" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - eplrs = True - - -@vehiclemod -class Tracma_TD_1500(unittype.VehicleType): - id = "Tracma" - name = "Tracma TD 1500" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -## AIRDEFENCE - - -@vehiclemod -class SMOKE_SAM_IR(unittype.VehicleType): - id = "SMOKESAM" - name = "SMOKE SAM IR" - detection_range = 20000 - threat_range = 20000 - air_weapon_dist = 20000 - eplrs = True - - -@vehiclemod -class _53T2(unittype.VehicleType): - id = "AA20" - name = "53T2" - detection_range = 5000 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class TRM_2000_53T2(unittype.VehicleType): - id = "TRM2000_AA20" - name = "TRM-2000 53T2" - detection_range = 6000 - threat_range = 2000 - air_weapon_dist = 2000 - eplrs = True - - -@vehiclemod -class TRM_2000_PAMELA(unittype.VehicleType): - id = "TRMMISTRAL" - name = "TRM-2000 PAMELA" - detection_range = 8000 - threat_range = 10000 - air_weapon_dist = 10000 - eplrs = True - - -@vehiclemod -class Leclerc_Serie_XXI_Desert(unittype.VehicleType): - id = "Leclerc_XXI_Desert" - name = "Leclerc Série XXI Désert" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class AMX_13_75mm(unittype.VehicleType): - id = "AMX1375" - name = "AMX-13 75mm" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 3500 - - -@vehiclemod -class AMX_13_90mm(unittype.VehicleType): - id = "AMX1390" - name = "AMX-13 90mm" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 3500 - - -@vehiclemod -class VBCI(unittype.VehicleType): - id = "VBCI" - name = "VBCI" - detection_range = 0 - threat_range = 3500 - air_weapon_dist = 3500 - eplrs = True - - -@vehiclemod -class Char_T_62(unittype.VehicleType): - id = "T62" - name = "Char T-62" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class Char_T_64BV(unittype.VehicleType): - id = "T64BV" - name = "Char T-64BV" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class Char_T_72A(unittype.VehicleType): - id = "T72M" - name = "Char T-72A" - detection_range = 0 - threat_range = 4000 - air_weapon_dist = 4000 - - -@vehiclemod -class KORNET_ATGM(unittype.VehicleType): - id = "KORNET" - name = "KORNET ATGM" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -## INFANTRY - - -@vehiclemod -class Infantry_Soldier_JTAC(unittype.VehicleType): - id = "JTACFP" - name = "Infantry Soldier JTAC" - detection_range = 0 - threat_range = 500 - air_weapon_dist = 500 - - -## ARTILERY - - -@vehiclemod -class MO_120_RT(unittype.VehicleType): - id = "M120" - name = "MO 120 RT" - detection_range = 0 - threat_range = 15000 - air_weapon_dist = 15000 - - -@vehiclemod -class VAB_MORTIER(unittype.VehicleType): - id = "VAB_MORTIER" - name = "VAB MORTIER" - detection_range = 0 - threat_range = 15000 - air_weapon_dist = 15000 - eplrs = True diff --git a/pydcs_extensions/hercules/__init__.py b/pydcs_extensions/hercules/__init__.py deleted file mode 100644 index c291222ec..000000000 --- a/pydcs_extensions/hercules/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .hercules import * diff --git a/pydcs_extensions/hercules/hercules.py b/pydcs_extensions/hercules/hercules.py deleted file mode 100644 index 3730edfd1..000000000 --- a/pydcs_extensions/hercules/hercules.py +++ /dev/null @@ -1,1221 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class HerculesWeapons: - GAU_23A_Chain_Gun__30mm_ = { - "clsid": "{Herc_GAU_23A_Chain_Gun}", - "name": "GAU 23A Chain Gun (30mm)", - "weight": 595.9426, - } - Herc_AAA_GEPARD = { - "clsid": "Herc_AAA_GEPARD", - "name": "AAA GEPARD [34720lb]", - "weight": 15782, - } - Herc_AAA_Vulcan_M163_Air = { - "clsid": "Herc_AAA_Vulcan_M163_Air", - "name": "AAA Vulcan M163 Air [21666lb]", - "weight": 9848, - } - Herc_AAA_Vulcan_M163_Skid = { - "clsid": "Herc_AAA_Vulcan_M163_Skid", - "name": "AAA Vulcan M163 Skid [21577lb]", - "weight": 9808, - } - Herc_Ammo_AGM_154C_missiles = { - "clsid": "Herc_Ammo_AGM_154C_missiles", - "name": "Ammo AGM-154C*10 [10648lb]", - "weight": 4960, - } - Herc_Ammo_AGM_65D_missiles = { - "clsid": "Herc_Ammo_AGM_65D_missiles", - "name": "Ammo AGM-65D*10 [4800lb]", - "weight": 2300, - } - Herc_Ammo_AGM_65E_missiles = { - "clsid": "Herc_Ammo_AGM_65E_missiles", - "name": "Ammo AGM-65E*10 [6292lb]", - "weight": 2980, - } - Herc_Ammo_AGM_65G_missiles = { - "clsid": "Herc_Ammo_AGM_65G_missiles", - "name": "Ammo AGM-65G*10 [6622lb]", - "weight": 3130, - } - Herc_Ammo_AGM_65H_missiles = { - "clsid": "Herc_Ammo_AGM_65H_missiles", - "name": "Ammo AGM-65H*10 [4570lb]", - "weight": 2200, - } - Herc_Ammo_AGM_65K_missiles = { - "clsid": "Herc_Ammo_AGM_65K_missiles", - "name": "Ammo AGM-65K*10 [7920lb]", - "weight": 3720, - } - Herc_Ammo_AGM_84A_missiles = { - "clsid": "Herc_Ammo_AGM_84A_missiles", - "name": "Ammo AGM-84A*8 [11651lb]", - "weight": 5408, - } - Herc_Ammo_AGM_84E_missiles = { - "clsid": "Herc_Ammo_AGM_84E_missiles", - "name": "Ammo AGM-84E*8 [11651lb]", - "weight": 5408, - } - Herc_Ammo_AGM_88C_missiles = { - "clsid": "Herc_Ammo_AGM_88C_missiles", - "name": "Ammo AGM-88C*10 [7920lb]", - "weight": 3730, - } - Herc_Ammo_AIM120B_missiles = { - "clsid": "Herc_Ammo_AIM120B_missiles", - "name": "Ammo AIM-120B*24 [11193lb]", - "weight": 5208, - } - Herc_Ammo_AIM120C_missiles = { - "clsid": "Herc_Ammo_AIM120C_missiles", - "name": "Ammo AIM-120C*24 [10665lb]", - "weight": 5208, - } - Herc_Ammo_AIM54C_missiles = { - "clsid": "Herc_Ammo_AIM54C_missiles", - "name": "Ammo AIM-54C*18 [18335lb]", - "weight": 8454, - } - Herc_Ammo_AIM7M_missiles = { - "clsid": "Herc_Ammo_AIM7M_missiles", - "name": "Ammo AIM-7M*24 [14995lb]", - "weight": 6936, - } - Herc_Ammo_AIM9M_missiles = { - "clsid": "Herc_Ammo_AIM9M_missiles", - "name": "Ammo AIM-9M*30 [7128lb]", - "weight": 4860, - } - Herc_Ammo_AIM9P5_missiles = { - "clsid": "Herc_Ammo_AIM9P5_missiles", - "name": "Ammo AIM-9P5*30 [5676lb]", - "weight": 2700, - } - Herc_Ammo_AIM9X_missiles = { - "clsid": "Herc_Ammo_AIM9X_missiles", - "name": "Ammo AIM-9X*30 [5676lb]", - "weight": 2700, - } - Herc_Ammo_BETAB500SP_bombs = { - "clsid": "Herc_Ammo_BETAB500SP_bombs", - "name": "Ammo BetAB-500ShP*10 [9328lb]", - "weight": 4360, - } - Herc_Ammo_BETAB500_bombs = { - "clsid": "Herc_Ammo_BETAB500_bombs", - "name": "Ammo BetAB-500*10 [9460lb]", - "weight": 4420, - } - Herc_Ammo_CBU_103_bombs = { - "clsid": "Herc_Ammo_CBU_103_bombs", - "name": "Ammo CBU-103*10 [10142lb]", - "weight": 4730, - } - Herc_Ammo_CBU_105_bombs = { - "clsid": "Herc_Ammo_CBU_105_bombs", - "name": "Ammo CBU-105*10 [11022lb]", - "weight": 5130, - } - Herc_Ammo_CBU_87_bombs = { - "clsid": "Herc_Ammo_CBU_87_bombs", - "name": "Ammo CBU-87*10 [9460lb]", - "weight": 4420, - } - Herc_Ammo_CBU_97_bombs = { - "clsid": "Herc_Ammo_CBU_97_bombs", - "name": "Ammo CBU-97*10 [10362lb]", - "weight": 4830, - } - Herc_Ammo_FAB100_bombs = { - "clsid": "Herc_Ammo_FAB100_bombs", - "name": "Ammo FAB-100*20 [4400lb", - "weight": 2120, - } - Herc_Ammo_FAB250_bombs = { - "clsid": "Herc_Ammo_FAB250_bombs", - "name": "Ammo FAB-250*20 [11000lb]", - "weight": 5120, - } - Herc_Ammo_FAB500_bombs = { - "clsid": "Herc_Ammo_FAB500_bombs", - "name": "Ammo FAB-500*10 [11000lb]", - "weight": 5120, - } - Herc_Ammo_GBU_10_bombs = { - "clsid": "Herc_Ammo_GBU_10_bombs", - "name": "Ammo GBU-10*6 [15340lb]", - "weight": 7092, - } - Herc_Ammo_GBU_12_bombs = { - "clsid": "Herc_Ammo_GBU_12_bombs", - "name": "Ammo GBU-12*16 [9680lb]", - "weight": 4520, - } - Herc_Ammo_GBU_16_bombs = { - "clsid": "Herc_Ammo_GBU_16_bombs", - "name": "Ammo GBU-16*10 [12408lb]", - "weight": 5760, - } - Herc_Ammo_GBU_31_V3B_bombs = { - "clsid": "Herc_Ammo_GBU_31_V3B_bombs", - "name": "Ammo GBU-31V3B*6 [12949lb]", - "weight": 6006, - } - Herc_Ammo_GBU_31_VB_bombs = { - "clsid": "Herc_Ammo_GBU_31_VB_bombs", - "name": "Ammo GBU-31V/B*6 [12328lb]", - "weight": 5724, - } - Herc_Ammo_GBU_38_bombs = { - "clsid": "Herc_Ammo_GBU_38_bombs", - "name": "Ammo GBU-38*10 [6028lb]", - "weight": 2860, - } - Herc_Ammo_hydra_HE_rockets = { - "clsid": "Herc_Ammo_hydra_HE_rockets", - "name": "Ammo M151 Hydra HE*80 [4752lb]", - "weight": 2280, - } - Herc_Ammo_hydra_WP_rockets = { - "clsid": "Herc_Ammo_hydra_WP_rockets", - "name": "Ammo M156 Hydra WP*80 [4752lb]", - "weight": 2280, - } - Herc_Ammo_KAB500KR_bombs = { - "clsid": "Herc_Ammo_KAB500KR_bombs", - "name": "Ammo KAB-500kr*10 [12320lb]", - "weight": 5720, - } - Herc_Ammo_KH25ML_missiles = { - "clsid": "Herc_Ammo_KH25ML_missiles", - "name": "Ammo Kh-25ML*10 [7920lb]", - "weight": 3720, - } - Herc_Ammo_KH25MPU_missiles = { - "clsid": "Herc_Ammo_KH25MPU_missiles", - "name": "Ammo Kh-25MPU*10 [8140lb]", - "weight": 3820, - } - Herc_Ammo_KH29L_missiles = { - "clsid": "Herc_Ammo_KH29L_missiles", - "name": "Ammo Kh-29L*10 [16434lb]", - "weight": 7590, - } - Herc_Ammo_KH29T_missiles = { - "clsid": "Herc_Ammo_KH29T_missiles", - "name": "Ammo Kh-29T*10 [16720lb]", - "weight": 7720, - } - Herc_Ammo_KH58U_missiles = { - "clsid": "Herc_Ammo_KH58U_missiles", - "name": "Ammo Kh-58U*10 [16060lb]", - "weight": 7420, - } - Herc_Ammo_KMGU296AO25KO_bombs = { - "clsid": "Herc_Ammo_KMGU296AO25KO_bombs", - "name": "Ammo KMGU-2 - 96 PTAB-2.5KO*10 [11440lb]", - "weight": 5320, - } - Herc_Ammo_KMGU296AO25RT_bombs = { - "clsid": "Herc_Ammo_KMGU296AO25RT_bombs", - "name": "Ammo KMGU-2 - 96 AO-2.5RT*10 [11440lb]", - "weight": 5320, - } - Herc_Ammo_M117_bombs = { - "clsid": "Herc_Ammo_M117_bombs", - "name": "Ammo M117*16 [11968lb]", - "weight": 5560, - } - Herc_Ammo_MAGIC2_missiles = { - "clsid": "Herc_Ammo_MAGIC2_missiles", - "name": "Ammo Magic2*30 [5676lb]", - "weight": 2700, - } - Herc_Ammo_MK20_bombs = { - "clsid": "Herc_Ammo_MK20_bombs", - "name": "Ammo MK20*20 [9768lb]", - "weight": 4560, - } - Herc_Ammo_Mk_82AIR_bombs = { - "clsid": "Herc_Ammo_Mk_82AIR_bombs", - "name": "Ammo Mk-82AIR*20 [11044lb]", - "weight": 4940, - } - Herc_Ammo_Mk_82Snake_bombs = { - "clsid": "Herc_Ammo_Mk_82Snake_bombs", - "name": "Ammo Mk-82Snakeye*20 [11880lb]", - "weight": 4940, - } - Herc_Ammo_Mk_82_bombs = { - "clsid": "Herc_Ammo_Mk_82_bombs", - "name": "Ammo Mk-82*20 [10560lb]", - "weight": 4940, - } - Herc_Ammo_Mk_83_bombs = { - "clsid": "Herc_Ammo_Mk_83_bombs", - "name": "Ammo Mk-83*10 [9834lb]", - "weight": 4590, - } - Herc_Ammo_Mk_84_bombs = { - "clsid": "Herc_Ammo_Mk_84_bombs", - "name": "Ammo Mk-84*8 [15735b]", - "weight": 7272, - } - Herc_Ammo_R27ER_missiles = { - "clsid": "Herc_Ammo_R27ER_missiles", - "name": "Ammo R-27ER*24 [18480lb]", - "weight": 8520, - } - Herc_Ammo_R27ET_missiles = { - "clsid": "Herc_Ammo_R27ET_missiles", - "name": "Ammo R-27ET*24 [18480lb", - "weight": 8496, - } - Herc_Ammo_R27R_missiles = { - "clsid": "Herc_Ammo_R27R_missiles", - "name": "Ammo R-27R*24 [13359lb]", - "weight": 6192, - } - Herc_Ammo_R27T_missiles = { - "clsid": "Herc_Ammo_R27T_missiles", - "name": "Ammo R-27T*24 [13359lb]", - "weight": 6192, - } - Herc_Ammo_R60M_missiles = { - "clsid": "Herc_Ammo_R60M_missiles", - "name": "Ammo R-60M*30 [2904lb]", - "weight": 1440, - } - Herc_Ammo_R77_missiles = { - "clsid": "Herc_Ammo_R77_missiles", - "name": "Ammo R-77*24 [9240lb]", - "weight": 4320, - } - Herc_Ammo_RBK250PTAB25M_bombs = { - "clsid": "Herc_Ammo_RBK250PTAB25M_bombs", - "name": "Ammo RBK-250 PTAB-2.5M*20 [12012lb]", - "weight": 5580, - } - Herc_Ammo_RBK500255PTAB105_bombs = { - "clsid": "Herc_Ammo_RBK500255PTAB105_bombs", - "name": "Ammo RBK-500-255 PTAB-10-5*10 [9394lb]", - "weight": 4390, - } - Herc_Ammo_RBK500PTAB1M_bombs = { - "clsid": "Herc_Ammo_RBK500PTAB1M_bombs", - "name": "Ammo RBK-500 PTAB-1M*10 [9394lb]", - "weight": 4390, - } - Herc_Ammo_S24B_missiles = { - "clsid": "Herc_Ammo_S24B_missiles", - "name": "Ammo S-24B*20 [10340lb]", - "weight": 4820, - } - Herc_Ammo_S25L_missiles = { - "clsid": "Herc_Ammo_S25L_missiles", - "name": "Ammo S-25L*10 [11000b]", - "weight": 5120, - } - Herc_Ammo_S25OFM_missiles = { - "clsid": "Herc_Ammo_S25OFM_missiles", - "name": "Ammo S-25OFM*10 [10890lb]", - "weight": 5070, - } - Herc_Ammo_S530D_missiles = { - "clsid": "Herc_Ammo_S530D_missiles", - "name": "Ammo Super 530D*24 [6480lb]", - "weight": 6600, - } - Herc_Ammo_SAB100_bombs = { - "clsid": "Herc_Ammo_SAB100_bombs", - "name": "Ammo SAB-100*20 [11000lb]", - "weight": 2120, - } - Herc_Ammo_TOW_missiles = { - "clsid": "Herc_Ammo_TOW_missiles", - "name": "Ammo TOW*30 [4125lb]", - "weight": 1980, - } - Herc_Ammo_Vikhr_missiles = { - "clsid": "Herc_Ammo_Vikhr_missiles", - "name": "Ammo Vikhr*48 [5808lb]", - "weight": 2760, - } - Herc_APC_BTR_80_Air = { - "clsid": "Herc_APC_BTR_80_Air", - "name": "APC BTR-80 Air [23936lb]", - "weight": 10880, - } - Herc_APC_BTR_80_Skid = { - "clsid": "Herc_APC_BTR_80_Skid", - "name": "APC BTR-80 Skid [23826lb]", - "weight": 10830, - } - Herc_APC_BTR_82A_Air = { - "clsid": "Herc_APC_BTR_82A_Air", - "name": "APC BTR-82A Air [24998lb]", - "weight": 11363, - } - Herc_APC_BTR_82A_Skid = { - "clsid": "Herc_APC_BTR_82A_Skid", - "name": "APC BTR-82A Skid [24888lb]", - "weight": 11313, - } - Herc_APC_COBRA_Air = { - "clsid": "Herc_APC_COBRA_Air", - "name": "APC Cobra Air [10912lb]", - "weight": 4960, - } - Herc_APC_COBRA_Skid = { - "clsid": "Herc_APC_COBRA_Skid", - "name": "APC Cobra Skid [10802lb]", - "weight": 4910, - } - Herc_APC_LAV_25_Air = { - "clsid": "Herc_APC_LAV_25_Air", - "name": "APC LAV-25 Air [22520lb]", - "weight": 10254, - } - Herc_APC_LAV_25_Skid = { - "clsid": "Herc_APC_LAV_25_Skid", - "name": "APC LAV-25 Skid [22514lb]", - "weight": 10234, - } - Herc_APC_M1025_HMMWV_Air = { - "clsid": "Herc_APC_M1025_HMMWV_Air", - "name": "M1025 HMMWV Air [6160lb]", - "weight": 2800, - } - Herc_APC_M1025_HMMWV_Skid = { - "clsid": "Herc_APC_M1025_HMMWV_Skid", - "name": "M1025 HMMWV Skid [6050lb]", - "weight": 2750, - } - Herc_APC_M1043_HMMWV_Armament_Air = { - "clsid": "Herc_APC_M1043_HMMWV_Armament_Air", - "name": "APC M1043 HMMWV Armament Air [7023lb]", - "weight": 3192, - } - Herc_APC_M1043_HMMWV_Armament_Skid = { - "clsid": "Herc_APC_M1043_HMMWV_Armament_Skid", - "name": "APC M1043 HMMWV Armament Skid [6912lb]", - "weight": 3142, - } - Herc_APC_M113_Air = { - "clsid": "Herc_APC_M113_Air", - "name": "APC M113 Air [21624lb]", - "weight": 9830, - } - Herc_APC_M113_Skid = { - "clsid": "Herc_APC_M113_Skid", - "name": "APC M113 Skid [21494lb]", - "weight": 9770, - } - Herc_APC_MTLB_Air = { - "clsid": "Herc_APC_MTLB_Air", - "name": "APC MTLB Air [26400lb]", - "weight": 12000, - } - Herc_APC_MTLB_Skid = { - "clsid": "Herc_APC_MTLB_Skid", - "name": "APC MTLB Skid [26290lb]", - "weight": 11950, - } - Herc_ART_GVOZDIKA = { - "clsid": "Herc_ART_GVOZDIKA", - "name": "ART GVOZDIKA [34720lb]", - "weight": 15782, - } - Herc_ART_NONA_Air = { - "clsid": "Herc_ART_NONA_Air", - "name": "ART 2S9 NONA Air [19140lb]", - "weight": 8700, - } - Herc_ART_NONA_Skid = { - "clsid": "Herc_ART_NONA_Skid", - "name": "ART 2S9 NONA Skid [19030lb]", - "weight": 8650, - } - Herc_ARV_BRDM_2_Air = { - "clsid": "Herc_ARV_BRDM_2_Air", - "name": "ARV BRDM-2 Air [12320lb]", - "weight": 5600, - } - Herc_ARV_BRDM_2_Skid = { - "clsid": "Herc_ARV_BRDM_2_Skid", - "name": "ARV BRDM-2 Skid [12210lb]", - "weight": 5550, - } - Herc_ATGM_M1045_HMMWV_TOW_Air = { - "clsid": "Herc_ATGM_M1045_HMMWV_TOW_Air", - "name": "ATGM M1045 HMMWV TOW Air [7183lb]", - "weight": 3265, - } - Herc_ATGM_M1045_HMMWV_TOW_Skid = { - "clsid": "Herc_ATGM_M1045_HMMWV_TOW_Skid", - "name": "ATGM M1045 HMMWV TOW Skid [7073lb]", - "weight": 3215, - } - Herc_ATGM_M1134_Stryker = { - "clsid": "Herc_ATGM_M1134_Stryker", - "name": "ATGM M1134 Stryker [30337lb]", - "weight": 13790, - } - Herc_BattleStation = { - "clsid": "Herc_BattleStation", - "name": "Battle Station", - "weight": 1160, - } - Herc_BattleStation_TGP = { - "clsid": "Herc_BattleStation_TGP", - "name": "Battle Station with TGP", - "weight": 1160, - } - Herc_EWR_SBORKA_Air = { - "clsid": "Herc_EWR_SBORKA_Air", - "name": "EWR SBORKA Air [21624lb]", - "weight": 9829, - } - Herc_EWR_SBORKA_Skid = { - "clsid": "Herc_EWR_SBORKA_Skid", - "name": "EWR SBORKA Skid [21624lb]", - "weight": 9829, - } - Herc_Ext_Fuel_Tank = { - "clsid": "Herc_Ext_Fuel_Tank", - "name": "External Fuel Tank", - "weight": 4131, - } - Herc_GBU_43_B_MOAB_ = { - "clsid": "Herc_GBU-43/B(MOAB)", - "name": "GBU-43/B(MOAB)", - "weight": 9800, - } - Herc_GEN_CRATE = { - "clsid": "Herc_GEN_CRATE", - "name": "Generic Crate [20000lb]", - "weight": 9071, - } - Herc_HEMTT_TFFT = { - "clsid": "Herc_HEMTT_TFFT", - "name": "HEMTT TFFT [34400lb]", - "weight": 15634, - } - Herc_IFV_BMD1_Air = { - "clsid": "Herc_IFV_BMD1_Air", - "name": "IFV BMD-1 Air [18040lb]", - "weight": 8200, - } - Herc_IFV_BMD1_Skid = { - "clsid": "Herc_IFV_BMD1_Skid", - "name": "IFV BMD-1 Skid [17930lb]", - "weight": 8150, - } - Herc_IFV_BMP_1 = { - "clsid": "Herc_IFV_BMP_1", - "name": "IFV BMP-1 [23232lb]", - "weight": 10560, - } - Herc_IFV_BMP_2 = { - "clsid": "Herc_IFV_BMP_2", - "name": "IFV BMP-2 [25168lb]", - "weight": 11440, - } - Herc_IFV_BMP_3 = { - "clsid": "Herc_IFV_BMP_3", - "name": "IFV BMP-3 [32912lb]", - "weight": 14960, - } - Herc_IFV_BTRD_Air = { - "clsid": "Herc_IFV_BTRD_Air", - "name": "IFV BTR-D Air [18040lb]", - "weight": 8200, - } - Herc_IFV_BTRD_Skid = { - "clsid": "Herc_IFV_BTRD_Skid", - "name": "IFV BTR-D Skid [17930lb]", - "weight": 8150, - } - Herc_IFV_M2A2_Bradley = { - "clsid": "Herc_IFV_M2A2_Bradley", - "name": "IFV M2A2 Bradley [34720lb]", - "weight": 15782, - } - Herc_IFV_MARDER = { - "clsid": "Herc_IFV_MARDER", - "name": "IFV MARDER [34720lb]", - "weight": 15782, - } - Herc_IFV_MCV80_Warrior = { - "clsid": "Herc_IFV_MCV80_Warrior", - "name": "IFV MCV-80 [34720lb]", - "weight": 15782, - } - Herc_IFV_TPZ = { - "clsid": "Herc_IFV_TPZ", - "name": "IFV TPZ FUCH [33440lb]", - "weight": 15200, - } - Herc_JATO = {"clsid": "Herc_JATO", "name": "JATO", "weight": 200} - Herc_M_818 = { - "clsid": "Herc_M_818", - "name": "Transport M818 [16000lb]", - "weight": 7272, - } - Herc_SAM_13 = { - "clsid": "Herc_SAM_13", - "name": "SAM SA-13 STRELA [21624lb]", - "weight": 9830, - } - Herc_SAM_19 = { - "clsid": "Herc_SAM_19", - "name": "SAM SA-19 Tunguska 2S6 [34720lb]", - "weight": 15782, - } - Herc_SAM_CHAPARRAL_Air = { - "clsid": "Herc_SAM_CHAPARRAL_Air", - "name": "SAM CHAPARRAL Air [21624lb]", - "weight": 9830, - } - Herc_SAM_CHAPARRAL_Skid = { - "clsid": "Herc_SAM_CHAPARRAL_Skid", - "name": "SAM CHAPARRAL Skid [21516lb]", - "weight": 9780, - } - Herc_SAM_LINEBACKER = { - "clsid": "Herc_SAM_LINEBACKER", - "name": "SAM LINEBACKER [34720lb]", - "weight": 15782, - } - Herc_SAM_M1097_HMMWV_Air = { - "clsid": "Herc_SAM_M1097_HMMWV_Air", - "name": "SAM Avenger M1097 Air [7200lb]", - "weight": 3273, - } - Herc_SAM_M1097_HMMWV_Skid = { - "clsid": "Herc_SAM_M1097_HMMWV_Skid", - "name": "SAM Avenger M1097 Skid [7090lb]", - "weight": 3223, - } - Herc_SAM_ROLAND_ADS = { - "clsid": "Herc_SAM_ROLAND_ADS", - "name": "SAM ROLAND ADS [34720lb]", - "weight": 15782, - } - Herc_SAM_ROLAND_LN = { - "clsid": "Herc_SAM_ROLAND_LN", - "name": "SAM ROLAND LN [34720b]", - "weight": 15782, - } - Herc_Soldier_Squad = { - "clsid": "Herc_Soldier_Squad", - "name": "Squad 30 x Soldier [7950lb]", - "weight": 120, - } - Herc_SPG_M1126_Stryker_ICV = { - "clsid": "Herc_SPG_M1126_Stryker_ICV", - "name": "APC M1126 Stryker ICV [29542lb]", - "weight": 13429, - } - Herc_SPG_M1128_Stryker_MGS = { - "clsid": "Herc_SPG_M1128_Stryker_MGS", - "name": "SPG M1128 Stryker MGS [33036lb]", - "weight": 15016, - } - Herc_Tanker_HEMTT = { - "clsid": "Herc_Tanker_HEMTT", - "name": "Tanker M978 HEMTT [34000lb]", - "weight": 15455, - } - Herc_TIGR_233036_Air = { - "clsid": "Herc_TIGR_233036_Air", - "name": "Transport Tigr Air [15900lb]", - "weight": 7200, - } - Herc_TIGR_233036_Skid = { - "clsid": "Herc_TIGR_233036_Skid", - "name": "Transport Tigr Skid [15730lb]", - "weight": 7150, - } - Herc_UAZ_469_Air = { - "clsid": "Herc_UAZ_469_Air", - "name": "Transport UAZ-469 Air [3747lb]", - "weight": 1700, - } - Herc_UAZ_469_Skid = { - "clsid": "Herc_UAZ_469_Skid", - "name": "Transport UAZ-469 Skid [3630lb]", - "weight": 1650, - } - Herc_URAL_375 = { - "clsid": "Herc_URAL_375", - "name": "Transport URAL-375 [14815lb]", - "weight": 6734, - } - Herc_ZSU_23_4 = { - "clsid": "Herc_ZSU_23_4", - "name": "AAA ZSU-23-4 Shilka [32912lb]", - "weight": 14960, - } - M61_Vulcan_Rotary_Cannon__20mm_ = { - "clsid": "{Herc_M61_Vulcan_Rotary_Cannon}", - "name": "M61 Vulcan Rotary Cannon (20mm)", - "weight": 595.9426, - } - _105mm_Howitzer = { - "clsid": "{Herc_105mm_Howitzer}", - "name": "105mm Howitzer", - "weight": 595.9426, - } - - -inject_weapons(HerculesWeapons) - - -@planemod -class Hercules(PlaneType): - id = "Hercules" - flyable = True - height = 11.84 - width = 40.41 - length = 34.36 - fuel_max = 19759 - max_speed = 669.6 - chaff = 840 - flare = 840 - charge_total = 1680 - chaff_charge_size = 1 - flare_charge_size = 1 - radio_frequency = 305 - - panel_radio = { - 1: { - "channels": { - 1: 305, - 2: 264, - 4: 256, - 8: 257, - 16: 261, - 17: 267, - 9: 255, - 18: 251, - 5: 254, - 10: 262, - 20: 266, - 11: 259, - 3: 265, - 6: 250, - 12: 252, - 13: 269, - 7: 270, - 14: 260, - 19: 253, - 15: 263, - }, - }, - } - - livery_name = "HERCULES" # from type - - class Pylon1: - Herc_JATO = (1, HerculesWeapons.Herc_JATO) - - class Pylon2: - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - Smokewinder___red = (2, Weapons.Smokewinder___red) - Smokewinder___green = (2, Weapons.Smokewinder___green) - Smokewinder___blue = (2, Weapons.Smokewinder___blue) - Smokewinder___white = (2, Weapons.Smokewinder___white) - Smokewinder___yellow = (2, Weapons.Smokewinder___yellow) - Smokewinder___orange = (2, Weapons.Smokewinder___orange) - MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD = ( - 2, - Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD, - ) - Herc_Ext_Fuel_Tank = (2, HerculesWeapons.Herc_Ext_Fuel_Tank) - - class Pylon3: - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - Smokewinder___red = (3, Weapons.Smokewinder___red) - Smokewinder___green = (3, Weapons.Smokewinder___green) - Smokewinder___blue = (3, Weapons.Smokewinder___blue) - Smokewinder___white = (3, Weapons.Smokewinder___white) - Smokewinder___yellow = (3, Weapons.Smokewinder___yellow) - Smokewinder___orange = (3, Weapons.Smokewinder___orange) - MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD = ( - 3, - Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD, - ) - Herc_Ext_Fuel_Tank = (3, HerculesWeapons.Herc_Ext_Fuel_Tank) - - class Pylon4: - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 4, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - Smokewinder___red = (4, Weapons.Smokewinder___red) - Smokewinder___green = (4, Weapons.Smokewinder___green) - Smokewinder___blue = (4, Weapons.Smokewinder___blue) - Smokewinder___white = (4, Weapons.Smokewinder___white) - Smokewinder___yellow = (4, Weapons.Smokewinder___yellow) - Smokewinder___orange = (4, Weapons.Smokewinder___orange) - MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD = ( - 4, - Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD, - ) - Herc_Ext_Fuel_Tank = (4, HerculesWeapons.Herc_Ext_Fuel_Tank) - - class Pylon5: - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - Smokewinder___red = (5, Weapons.Smokewinder___red) - Smokewinder___green = (5, Weapons.Smokewinder___green) - Smokewinder___blue = (5, Weapons.Smokewinder___blue) - Smokewinder___white = (5, Weapons.Smokewinder___white) - Smokewinder___yellow = (5, Weapons.Smokewinder___yellow) - Smokewinder___orange = (5, Weapons.Smokewinder___orange) - MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD = ( - 5, - Weapons.MER6_with_6_x_Mk_82___500lb_GP_Bombs_LD, - ) - Herc_Ext_Fuel_Tank = (5, HerculesWeapons.Herc_Ext_Fuel_Tank) - - class Pylon6: - M61_Vulcan_Rotary_Cannon__20mm_ = ( - 6, - HerculesWeapons.M61_Vulcan_Rotary_Cannon__20mm_, - ) - - class Pylon7: - GAU_23A_Chain_Gun__30mm_ = (7, HerculesWeapons.GAU_23A_Chain_Gun__30mm_) - - class Pylon8: - _105mm_Howitzer = (8, HerculesWeapons._105mm_Howitzer) - - class Pylon9: - Herc_BattleStation = (9, HerculesWeapons.Herc_BattleStation) - Herc_BattleStation_TGP = (9, HerculesWeapons.Herc_BattleStation_TGP) - - class Pylon10: - Herc_Ammo_AGM_65D_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_65D_missiles) - Herc_Ammo_AGM_65H_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_65H_missiles) - Herc_Ammo_AGM_65G_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_65G_missiles) - Herc_Ammo_AGM_65E_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_65E_missiles) - Herc_Ammo_AGM_88C_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_88C_missiles) - Herc_Ammo_AGM_65K_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_65K_missiles) - Herc_Ammo_Vikhr_missiles = (10, HerculesWeapons.Herc_Ammo_Vikhr_missiles) - Herc_Ammo_AGM_84A_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_84A_missiles) - Herc_Ammo_AGM_84E_missiles = (10, HerculesWeapons.Herc_Ammo_AGM_84E_missiles) - Herc_Ammo_KH25ML_missiles = (10, HerculesWeapons.Herc_Ammo_KH25ML_missiles) - Herc_Ammo_KH25MPU_missiles = (10, HerculesWeapons.Herc_Ammo_KH25MPU_missiles) - Herc_Ammo_KH29T_missiles = (10, HerculesWeapons.Herc_Ammo_KH29T_missiles) - Herc_Ammo_KH29L_missiles = (10, HerculesWeapons.Herc_Ammo_KH29L_missiles) - Herc_Ammo_KH58U_missiles = (10, HerculesWeapons.Herc_Ammo_KH58U_missiles) - Herc_Ammo_S24B_missiles = (10, HerculesWeapons.Herc_Ammo_S24B_missiles) - Herc_Ammo_S25OFM_missiles = (10, HerculesWeapons.Herc_Ammo_S25OFM_missiles) - Herc_Ammo_S25L_missiles = (10, HerculesWeapons.Herc_Ammo_S25L_missiles) - Herc_Ammo_TOW_missiles = (10, HerculesWeapons.Herc_Ammo_TOW_missiles) - Herc_Ammo_GBU_10_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_10_bombs) - Herc_Ammo_GBU_12_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_12_bombs) - Herc_Ammo_GBU_16_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_16_bombs) - Herc_Ammo_GBU_31_VB_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_31_VB_bombs) - Herc_Ammo_GBU_31_V3B_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_31_V3B_bombs) - Herc_Ammo_GBU_38_bombs = (10, HerculesWeapons.Herc_Ammo_GBU_38_bombs) - Herc_Ammo_CBU_87_bombs = (10, HerculesWeapons.Herc_Ammo_CBU_87_bombs) - Herc_Ammo_CBU_97_bombs = (10, HerculesWeapons.Herc_Ammo_CBU_97_bombs) - Herc_Ammo_CBU_103_bombs = (10, HerculesWeapons.Herc_Ammo_CBU_103_bombs) - Herc_Ammo_CBU_105_bombs = (10, HerculesWeapons.Herc_Ammo_CBU_105_bombs) - Herc_Ammo_Mk_82_bombs = (10, HerculesWeapons.Herc_Ammo_Mk_82_bombs) - Herc_Ammo_Mk_82AIR_bombs = (10, HerculesWeapons.Herc_Ammo_Mk_82AIR_bombs) - Herc_Ammo_Mk_82Snake_bombs = (10, HerculesWeapons.Herc_Ammo_Mk_82Snake_bombs) - Herc_Ammo_Mk_83_bombs = (10, HerculesWeapons.Herc_Ammo_Mk_83_bombs) - Herc_Ammo_Mk_84_bombs = (10, HerculesWeapons.Herc_Ammo_Mk_84_bombs) - Herc_Ammo_FAB100_bombs = (10, HerculesWeapons.Herc_Ammo_FAB100_bombs) - Herc_Ammo_FAB250_bombs = (10, HerculesWeapons.Herc_Ammo_FAB250_bombs) - Herc_Ammo_FAB500_bombs = (10, HerculesWeapons.Herc_Ammo_FAB500_bombs) - Herc_Ammo_BETAB500_bombs = (10, HerculesWeapons.Herc_Ammo_BETAB500_bombs) - Herc_Ammo_BETAB500SP_bombs = (10, HerculesWeapons.Herc_Ammo_BETAB500SP_bombs) - Herc_Ammo_KAB500KR_bombs = (10, HerculesWeapons.Herc_Ammo_KAB500KR_bombs) - Herc_Ammo_RBK250PTAB25M_bombs = ( - 10, - HerculesWeapons.Herc_Ammo_RBK250PTAB25M_bombs, - ) - Herc_Ammo_RBK500255PTAB105_bombs = ( - 10, - HerculesWeapons.Herc_Ammo_RBK500255PTAB105_bombs, - ) - Herc_Ammo_RBK500PTAB1M_bombs = ( - 10, - HerculesWeapons.Herc_Ammo_RBK500PTAB1M_bombs, - ) - # ERRR Herc_Ammo_Herc_Ammo_M117_bombs_bombs - Herc_Ammo_KMGU296AO25RT_bombs = ( - 10, - HerculesWeapons.Herc_Ammo_KMGU296AO25RT_bombs, - ) - Herc_Ammo_KMGU296AO25KO_bombs = ( - 10, - HerculesWeapons.Herc_Ammo_KMGU296AO25KO_bombs, - ) - Herc_Ammo_MK20_bombs = (10, HerculesWeapons.Herc_Ammo_MK20_bombs) - Herc_Ammo_SAB100_bombs = (10, HerculesWeapons.Herc_Ammo_SAB100_bombs) - Herc_Ammo_hydra_HE_rockets = (10, HerculesWeapons.Herc_Ammo_hydra_HE_rockets) - Herc_Ammo_hydra_WP_rockets = (10, HerculesWeapons.Herc_Ammo_hydra_WP_rockets) - Herc_Ammo_AIM9M_missiles = (10, HerculesWeapons.Herc_Ammo_AIM9M_missiles) - Herc_Ammo_AIM9P5_missiles = (10, HerculesWeapons.Herc_Ammo_AIM9P5_missiles) - Herc_Ammo_AIM9X_missiles = (10, HerculesWeapons.Herc_Ammo_AIM9X_missiles) - Herc_Ammo_AIM7M_missiles = (10, HerculesWeapons.Herc_Ammo_AIM7M_missiles) - Herc_Ammo_AIM120B_missiles = (10, HerculesWeapons.Herc_Ammo_AIM120B_missiles) - Herc_Ammo_AIM120C_missiles = (10, HerculesWeapons.Herc_Ammo_AIM120C_missiles) - Herc_Ammo_R60M_missiles = (10, HerculesWeapons.Herc_Ammo_R60M_missiles) - Herc_Ammo_MAGIC2_missiles = (10, HerculesWeapons.Herc_Ammo_MAGIC2_missiles) - Herc_Ammo_R27R_missiles = (10, HerculesWeapons.Herc_Ammo_R27R_missiles) - Herc_Ammo_R27ER_missiles = (10, HerculesWeapons.Herc_Ammo_R27ER_missiles) - Herc_Ammo_R27T_missiles = (10, HerculesWeapons.Herc_Ammo_R27T_missiles) - Herc_Ammo_R27ET_missiles = (10, HerculesWeapons.Herc_Ammo_R27ET_missiles) - # ERRR Herc_Ammo_R27_missiles - Herc_Ammo_S530D_missiles = (10, HerculesWeapons.Herc_Ammo_S530D_missiles) - Herc_Ammo_AIM54C_missiles = (10, HerculesWeapons.Herc_Ammo_AIM54C_missiles) - Herc_APC_M1043_HMMWV_Armament_Air = ( - 10, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Air, - ) - Herc_ATGM_M1045_HMMWV_TOW_Air = ( - 10, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Air, - ) - Herc_APC_M1025_HMMWV_Air = (10, HerculesWeapons.Herc_APC_M1025_HMMWV_Air) - Herc_SAM_M1097_HMMWV_Air = (10, HerculesWeapons.Herc_SAM_M1097_HMMWV_Air) - Herc_APC_COBRA_Air = (10, HerculesWeapons.Herc_APC_COBRA_Air) - Herc_APC_COBRA_Skid = (10, HerculesWeapons.Herc_APC_COBRA_Skid) - Herc_ARV_BRDM_2_Air = (10, HerculesWeapons.Herc_ARV_BRDM_2_Air) - Herc_TIGR_233036_Air = (10, HerculesWeapons.Herc_TIGR_233036_Air) - Herc_IFV_BMD1_Air = (10, HerculesWeapons.Herc_IFV_BMD1_Air) - Herc_IFV_BTRD_Air = (10, HerculesWeapons.Herc_IFV_BTRD_Air) - Herc_ART_NONA_Air = (10, HerculesWeapons.Herc_ART_NONA_Air) - Herc_APC_M1043_HMMWV_Armament_Skid = ( - 10, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Skid, - ) - Herc_ATGM_M1045_HMMWV_TOW_Skid = ( - 10, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Skid, - ) - Herc_APC_M1025_HMMWV_Skid = (10, HerculesWeapons.Herc_APC_M1025_HMMWV_Skid) - Herc_SAM_M1097_HMMWV_Skid = (10, HerculesWeapons.Herc_SAM_M1097_HMMWV_Skid) - Herc_ARV_BRDM_2_Skid = (10, HerculesWeapons.Herc_ARV_BRDM_2_Skid) - Herc_TIGR_233036_Skid = (10, HerculesWeapons.Herc_TIGR_233036_Skid) - Herc_IFV_BMD1_Skid = (10, HerculesWeapons.Herc_IFV_BMD1_Skid) - Herc_IFV_BTRD_Skid = (10, HerculesWeapons.Herc_IFV_BTRD_Skid) - Herc_ART_NONA_Skid = (10, HerculesWeapons.Herc_ART_NONA_Skid) - Herc_GEN_CRATE = (10, HerculesWeapons.Herc_GEN_CRATE) - Herc_UAZ_469_Air = (10, HerculesWeapons.Herc_UAZ_469_Air) - Herc_UAZ_469_Skid = (10, HerculesWeapons.Herc_UAZ_469_Skid) - - class Pylon11: - Herc_Ammo_AGM_65D_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_65D_missiles) - Herc_Ammo_AGM_65H_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_65H_missiles) - Herc_Ammo_AGM_65G_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_65G_missiles) - Herc_Ammo_AGM_65E_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_65E_missiles) - Herc_Ammo_AGM_88C_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_88C_missiles) - Herc_Ammo_AGM_65K_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_65K_missiles) - Herc_Ammo_Vikhr_missiles = (11, HerculesWeapons.Herc_Ammo_Vikhr_missiles) - Herc_Ammo_AGM_84A_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_84A_missiles) - Herc_Ammo_AGM_84E_missiles = (11, HerculesWeapons.Herc_Ammo_AGM_84E_missiles) - Herc_Ammo_KH25ML_missiles = (11, HerculesWeapons.Herc_Ammo_KH25ML_missiles) - Herc_Ammo_KH25MPU_missiles = (11, HerculesWeapons.Herc_Ammo_KH25MPU_missiles) - Herc_Ammo_KH29T_missiles = (11, HerculesWeapons.Herc_Ammo_KH29T_missiles) - Herc_Ammo_KH29L_missiles = (11, HerculesWeapons.Herc_Ammo_KH29L_missiles) - Herc_Ammo_KH58U_missiles = (11, HerculesWeapons.Herc_Ammo_KH58U_missiles) - Herc_Ammo_S24B_missiles = (11, HerculesWeapons.Herc_Ammo_S24B_missiles) - Herc_Ammo_S25OFM_missiles = (11, HerculesWeapons.Herc_Ammo_S25OFM_missiles) - Herc_Ammo_S25L_missiles = (11, HerculesWeapons.Herc_Ammo_S25L_missiles) - Herc_Ammo_TOW_missiles = (11, HerculesWeapons.Herc_Ammo_TOW_missiles) - Herc_GBU_43_B_MOAB_ = (11, HerculesWeapons.Herc_GBU_43_B_MOAB_) - Herc_Ammo_GBU_10_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_10_bombs) - Herc_Ammo_GBU_12_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_12_bombs) - Herc_Ammo_GBU_16_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_16_bombs) - Herc_Ammo_GBU_31_VB_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_31_VB_bombs) - Herc_Ammo_GBU_31_V3B_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_31_V3B_bombs) - Herc_Ammo_GBU_38_bombs = (11, HerculesWeapons.Herc_Ammo_GBU_38_bombs) - Herc_Ammo_CBU_87_bombs = (11, HerculesWeapons.Herc_Ammo_CBU_87_bombs) - Herc_Ammo_CBU_97_bombs = (11, HerculesWeapons.Herc_Ammo_CBU_97_bombs) - Herc_Ammo_CBU_103_bombs = (11, HerculesWeapons.Herc_Ammo_CBU_103_bombs) - Herc_Ammo_CBU_105_bombs = (11, HerculesWeapons.Herc_Ammo_CBU_105_bombs) - Herc_Ammo_Mk_82_bombs = (11, HerculesWeapons.Herc_Ammo_Mk_82_bombs) - Herc_Ammo_Mk_82AIR_bombs = (11, HerculesWeapons.Herc_Ammo_Mk_82AIR_bombs) - Herc_Ammo_Mk_82Snake_bombs = (11, HerculesWeapons.Herc_Ammo_Mk_82Snake_bombs) - Herc_Ammo_Mk_83_bombs = (11, HerculesWeapons.Herc_Ammo_Mk_83_bombs) - Herc_Ammo_Mk_84_bombs = (11, HerculesWeapons.Herc_Ammo_Mk_84_bombs) - Herc_Ammo_FAB100_bombs = (11, HerculesWeapons.Herc_Ammo_FAB100_bombs) - Herc_Ammo_FAB250_bombs = (11, HerculesWeapons.Herc_Ammo_FAB250_bombs) - Herc_Ammo_FAB500_bombs = (11, HerculesWeapons.Herc_Ammo_FAB500_bombs) - Herc_Ammo_BETAB500_bombs = (11, HerculesWeapons.Herc_Ammo_BETAB500_bombs) - Herc_Ammo_BETAB500SP_bombs = (11, HerculesWeapons.Herc_Ammo_BETAB500SP_bombs) - Herc_Ammo_KAB500KR_bombs = (11, HerculesWeapons.Herc_Ammo_KAB500KR_bombs) - Herc_Ammo_RBK250PTAB25M_bombs = ( - 11, - HerculesWeapons.Herc_Ammo_RBK250PTAB25M_bombs, - ) - Herc_Ammo_RBK500255PTAB105_bombs = ( - 11, - HerculesWeapons.Herc_Ammo_RBK500255PTAB105_bombs, - ) - Herc_Ammo_RBK500PTAB1M_bombs = ( - 11, - HerculesWeapons.Herc_Ammo_RBK500PTAB1M_bombs, - ) - # ERRR Herc_Ammo_Herc_Ammo_M117_bombs_bombs - Herc_Ammo_KMGU296AO25RT_bombs = ( - 11, - HerculesWeapons.Herc_Ammo_KMGU296AO25RT_bombs, - ) - Herc_Ammo_KMGU296AO25KO_bombs = ( - 11, - HerculesWeapons.Herc_Ammo_KMGU296AO25KO_bombs, - ) - Herc_Ammo_MK20_bombs = (11, HerculesWeapons.Herc_Ammo_MK20_bombs) - Herc_Ammo_SAB100_bombs = (11, HerculesWeapons.Herc_Ammo_SAB100_bombs) - Herc_Ammo_hydra_HE_rockets = (11, HerculesWeapons.Herc_Ammo_hydra_HE_rockets) - Herc_Ammo_hydra_WP_rockets = (11, HerculesWeapons.Herc_Ammo_hydra_WP_rockets) - Herc_Ammo_AIM9M_missiles = (11, HerculesWeapons.Herc_Ammo_AIM9M_missiles) - Herc_Ammo_AIM9P5_missiles = (11, HerculesWeapons.Herc_Ammo_AIM9P5_missiles) - Herc_Ammo_AIM9X_missiles = (11, HerculesWeapons.Herc_Ammo_AIM9X_missiles) - Herc_Ammo_AIM7M_missiles = (11, HerculesWeapons.Herc_Ammo_AIM7M_missiles) - Herc_Ammo_AIM120B_missiles = (11, HerculesWeapons.Herc_Ammo_AIM120B_missiles) - Herc_Ammo_AIM120C_missiles = (11, HerculesWeapons.Herc_Ammo_AIM120C_missiles) - Herc_Ammo_R60M_missiles = (11, HerculesWeapons.Herc_Ammo_R60M_missiles) - Herc_Ammo_MAGIC2_missiles = (11, HerculesWeapons.Herc_Ammo_MAGIC2_missiles) - Herc_Ammo_R27R_missiles = (11, HerculesWeapons.Herc_Ammo_R27R_missiles) - Herc_Ammo_R27ER_missiles = (11, HerculesWeapons.Herc_Ammo_R27ER_missiles) - Herc_Ammo_R27T_missiles = (11, HerculesWeapons.Herc_Ammo_R27T_missiles) - Herc_Ammo_R27ET_missiles = (11, HerculesWeapons.Herc_Ammo_R27ET_missiles) - # ERRR Herc_Ammo_R27_missiles - Herc_Ammo_S530D_missiles = (11, HerculesWeapons.Herc_Ammo_S530D_missiles) - Herc_Ammo_AIM54C_missiles = (11, HerculesWeapons.Herc_Ammo_AIM54C_missiles) - Herc_APC_M1043_HMMWV_Armament_Air = ( - 11, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Air, - ) - Herc_APC_M1043_HMMWV_Armament_Skid = ( - 11, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Skid, - ) - Herc_ATGM_M1045_HMMWV_TOW_Air = ( - 11, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Air, - ) - Herc_ATGM_M1045_HMMWV_TOW_Skid = ( - 11, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Skid, - ) - Herc_AAA_Vulcan_M163_Air = (11, HerculesWeapons.Herc_AAA_Vulcan_M163_Air) - Herc_AAA_Vulcan_M163_Skid = (11, HerculesWeapons.Herc_AAA_Vulcan_M163_Skid) - Herc_SPG_M1126_Stryker_ICV = (11, HerculesWeapons.Herc_SPG_M1126_Stryker_ICV) - Herc_SPG_M1128_Stryker_MGS = (11, HerculesWeapons.Herc_SPG_M1128_Stryker_MGS) - Herc_ATGM_M1134_Stryker = (11, HerculesWeapons.Herc_ATGM_M1134_Stryker) - Herc_APC_LAV_25_Air = (11, HerculesWeapons.Herc_APC_LAV_25_Air) - Herc_APC_LAV_25_Skid = (11, HerculesWeapons.Herc_APC_LAV_25_Skid) - Herc_SAM_M1097_HMMWV_Air = (11, HerculesWeapons.Herc_SAM_M1097_HMMWV_Air) - Herc_SAM_M1097_HMMWV_Skid = (11, HerculesWeapons.Herc_SAM_M1097_HMMWV_Skid) - Herc_APC_COBRA_Air = (11, HerculesWeapons.Herc_APC_COBRA_Air) - Herc_APC_COBRA_Skid = (11, HerculesWeapons.Herc_APC_COBRA_Skid) - Herc_APC_M113_Air = (11, HerculesWeapons.Herc_APC_M113_Air) - Herc_APC_M113_Skid = (11, HerculesWeapons.Herc_APC_M113_Skid) - Herc_Tanker_HEMTT = (11, HerculesWeapons.Herc_Tanker_HEMTT) - Herc_HEMTT_TFFT = (11, HerculesWeapons.Herc_HEMTT_TFFT) - Herc_IFV_M2A2_Bradley = (11, HerculesWeapons.Herc_IFV_M2A2_Bradley) - Herc_IFV_MCV80_Warrior = (11, HerculesWeapons.Herc_IFV_MCV80_Warrior) - Herc_IFV_BMP_1 = (11, HerculesWeapons.Herc_IFV_BMP_1) - Herc_IFV_BMP_2 = (11, HerculesWeapons.Herc_IFV_BMP_2) - Herc_IFV_BMP_3 = (11, HerculesWeapons.Herc_IFV_BMP_3) - Herc_ARV_BRDM_2_Air = (11, HerculesWeapons.Herc_ARV_BRDM_2_Air) - Herc_ARV_BRDM_2_Skid = (11, HerculesWeapons.Herc_ARV_BRDM_2_Skid) - Herc_APC_BTR_80_Air = (11, HerculesWeapons.Herc_APC_BTR_80_Air) - Herc_APC_BTR_80_Skid = (11, HerculesWeapons.Herc_APC_BTR_80_Skid) - Herc_SAM_ROLAND_ADS = (11, HerculesWeapons.Herc_SAM_ROLAND_ADS) - Herc_SAM_ROLAND_LN = (11, HerculesWeapons.Herc_SAM_ROLAND_LN) - Herc_SAM_13 = (11, HerculesWeapons.Herc_SAM_13) - Herc_ZSU_23_4 = (11, HerculesWeapons.Herc_ZSU_23_4) - Herc_SAM_19 = (11, HerculesWeapons.Herc_SAM_19) - Herc_URAL_375 = (11, HerculesWeapons.Herc_URAL_375) - Herc_M_818 = (11, HerculesWeapons.Herc_M_818) - Herc_SAM_CHAPARRAL_Air = (11, HerculesWeapons.Herc_SAM_CHAPARRAL_Air) - Herc_SAM_CHAPARRAL_Skid = (11, HerculesWeapons.Herc_SAM_CHAPARRAL_Skid) - Herc_SAM_LINEBACKER = (11, HerculesWeapons.Herc_SAM_LINEBACKER) - Herc_IFV_MARDER = (11, HerculesWeapons.Herc_IFV_MARDER) - Herc_IFV_TPZ = (11, HerculesWeapons.Herc_IFV_TPZ) - Herc_IFV_BMD1_Air = (11, HerculesWeapons.Herc_IFV_BMD1_Air) - Herc_IFV_BMD1_Skid = (11, HerculesWeapons.Herc_IFV_BMD1_Skid) - Herc_IFV_BTRD_Air = (11, HerculesWeapons.Herc_IFV_BTRD_Air) - Herc_IFV_BTRD_Skid = (11, HerculesWeapons.Herc_IFV_BTRD_Skid) - Herc_ART_GVOZDIKA = (11, HerculesWeapons.Herc_ART_GVOZDIKA) - Herc_ART_NONA_Air = (11, HerculesWeapons.Herc_ART_NONA_Air) - Herc_ART_NONA_Skid = (11, HerculesWeapons.Herc_ART_NONA_Skid) - Herc_APC_MTLB_Air = (11, HerculesWeapons.Herc_APC_MTLB_Air) - Herc_APC_MTLB_Skid = (11, HerculesWeapons.Herc_APC_MTLB_Skid) - Herc_GEN_CRATE = (11, HerculesWeapons.Herc_GEN_CRATE) - Herc_EWR_SBORKA_Air = (11, HerculesWeapons.Herc_EWR_SBORKA_Air) - Herc_EWR_SBORKA_Skid = (11, HerculesWeapons.Herc_EWR_SBORKA_Skid) - Herc_APC_BTR_82A_Air = (11, HerculesWeapons.Herc_APC_BTR_82A_Air) - Herc_APC_BTR_82A_Skid = (11, HerculesWeapons.Herc_APC_BTR_82A_Skid) - - class Pylon12: - Herc_Soldier_Squad = (12, HerculesWeapons.Herc_Soldier_Squad) - Herc_Ammo_AGM_65D_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_65D_missiles) - Herc_Ammo_AGM_65H_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_65H_missiles) - Herc_Ammo_AGM_65G_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_65G_missiles) - Herc_Ammo_AGM_65E_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_65E_missiles) - Herc_Ammo_AGM_88C_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_88C_missiles) - Herc_Ammo_AGM_65K_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_65K_missiles) - Herc_Ammo_Vikhr_missiles = (12, HerculesWeapons.Herc_Ammo_Vikhr_missiles) - Herc_Ammo_AGM_84A_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_84A_missiles) - Herc_Ammo_AGM_84E_missiles = (12, HerculesWeapons.Herc_Ammo_AGM_84E_missiles) - Herc_Ammo_KH25ML_missiles = (12, HerculesWeapons.Herc_Ammo_KH25ML_missiles) - Herc_Ammo_KH25MPU_missiles = (12, HerculesWeapons.Herc_Ammo_KH25MPU_missiles) - Herc_Ammo_KH29T_missiles = (12, HerculesWeapons.Herc_Ammo_KH29T_missiles) - Herc_Ammo_KH29L_missiles = (12, HerculesWeapons.Herc_Ammo_KH29L_missiles) - Herc_Ammo_KH58U_missiles = (12, HerculesWeapons.Herc_Ammo_KH58U_missiles) - Herc_Ammo_S24B_missiles = (12, HerculesWeapons.Herc_Ammo_S24B_missiles) - Herc_Ammo_S25OFM_missiles = (12, HerculesWeapons.Herc_Ammo_S25OFM_missiles) - Herc_Ammo_S25L_missiles = (12, HerculesWeapons.Herc_Ammo_S25L_missiles) - Herc_Ammo_TOW_missiles = (12, HerculesWeapons.Herc_Ammo_TOW_missiles) - Herc_Ammo_GBU_10_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_10_bombs) - Herc_Ammo_GBU_12_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_12_bombs) - Herc_Ammo_GBU_16_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_16_bombs) - Herc_Ammo_GBU_31_VB_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_31_VB_bombs) - Herc_Ammo_GBU_31_V3B_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_31_V3B_bombs) - Herc_Ammo_GBU_38_bombs = (12, HerculesWeapons.Herc_Ammo_GBU_38_bombs) - Herc_Ammo_CBU_87_bombs = (12, HerculesWeapons.Herc_Ammo_CBU_87_bombs) - Herc_Ammo_CBU_97_bombs = (12, HerculesWeapons.Herc_Ammo_CBU_97_bombs) - Herc_Ammo_CBU_103_bombs = (12, HerculesWeapons.Herc_Ammo_CBU_103_bombs) - Herc_Ammo_CBU_105_bombs = (12, HerculesWeapons.Herc_Ammo_CBU_105_bombs) - Herc_Ammo_Mk_82_bombs = (12, HerculesWeapons.Herc_Ammo_Mk_82_bombs) - Herc_Ammo_Mk_82AIR_bombs = (12, HerculesWeapons.Herc_Ammo_Mk_82AIR_bombs) - Herc_Ammo_Mk_82Snake_bombs = (12, HerculesWeapons.Herc_Ammo_Mk_82Snake_bombs) - Herc_Ammo_Mk_83_bombs = (12, HerculesWeapons.Herc_Ammo_Mk_83_bombs) - Herc_Ammo_Mk_84_bombs = (12, HerculesWeapons.Herc_Ammo_Mk_84_bombs) - Herc_Ammo_FAB100_bombs = (12, HerculesWeapons.Herc_Ammo_FAB100_bombs) - Herc_Ammo_FAB250_bombs = (12, HerculesWeapons.Herc_Ammo_FAB250_bombs) - Herc_Ammo_FAB500_bombs = (12, HerculesWeapons.Herc_Ammo_FAB500_bombs) - Herc_Ammo_BETAB500_bombs = (12, HerculesWeapons.Herc_Ammo_BETAB500_bombs) - Herc_Ammo_BETAB500SP_bombs = (12, HerculesWeapons.Herc_Ammo_BETAB500SP_bombs) - Herc_Ammo_KAB500KR_bombs = (12, HerculesWeapons.Herc_Ammo_KAB500KR_bombs) - Herc_Ammo_RBK250PTAB25M_bombs = ( - 12, - HerculesWeapons.Herc_Ammo_RBK250PTAB25M_bombs, - ) - Herc_Ammo_RBK500255PTAB105_bombs = ( - 12, - HerculesWeapons.Herc_Ammo_RBK500255PTAB105_bombs, - ) - Herc_Ammo_RBK500PTAB1M_bombs = ( - 12, - HerculesWeapons.Herc_Ammo_RBK500PTAB1M_bombs, - ) - # ERRR Herc_Ammo_Herc_Ammo_M117_bombs_bombs - Herc_Ammo_KMGU296AO25RT_bombs = ( - 12, - HerculesWeapons.Herc_Ammo_KMGU296AO25RT_bombs, - ) - Herc_Ammo_KMGU296AO25KO_bombs = ( - 12, - HerculesWeapons.Herc_Ammo_KMGU296AO25KO_bombs, - ) - Herc_Ammo_MK20_bombs = (12, HerculesWeapons.Herc_Ammo_MK20_bombs) - Herc_Ammo_SAB100_bombs = (12, HerculesWeapons.Herc_Ammo_SAB100_bombs) - Herc_Ammo_hydra_HE_rockets = (12, HerculesWeapons.Herc_Ammo_hydra_HE_rockets) - Herc_Ammo_hydra_WP_rockets = (12, HerculesWeapons.Herc_Ammo_hydra_WP_rockets) - Herc_Ammo_AIM9M_missiles = (12, HerculesWeapons.Herc_Ammo_AIM9M_missiles) - Herc_Ammo_AIM9P5_missiles = (12, HerculesWeapons.Herc_Ammo_AIM9P5_missiles) - Herc_Ammo_AIM9X_missiles = (12, HerculesWeapons.Herc_Ammo_AIM9X_missiles) - Herc_Ammo_AIM7M_missiles = (12, HerculesWeapons.Herc_Ammo_AIM7M_missiles) - Herc_Ammo_AIM120B_missiles = (12, HerculesWeapons.Herc_Ammo_AIM120B_missiles) - Herc_Ammo_AIM120C_missiles = (12, HerculesWeapons.Herc_Ammo_AIM120C_missiles) - Herc_Ammo_R60M_missiles = (12, HerculesWeapons.Herc_Ammo_R60M_missiles) - Herc_Ammo_MAGIC2_missiles = (12, HerculesWeapons.Herc_Ammo_MAGIC2_missiles) - Herc_Ammo_R27R_missiles = (12, HerculesWeapons.Herc_Ammo_R27R_missiles) - Herc_Ammo_R27ER_missiles = (12, HerculesWeapons.Herc_Ammo_R27ER_missiles) - Herc_Ammo_R27T_missiles = (12, HerculesWeapons.Herc_Ammo_R27T_missiles) - Herc_Ammo_R27ET_missiles = (12, HerculesWeapons.Herc_Ammo_R27ET_missiles) - # ERRR Herc_Ammo_R27_missiles - Herc_Ammo_S530D_missiles = (12, HerculesWeapons.Herc_Ammo_S530D_missiles) - Herc_Ammo_AIM54C_missiles = (12, HerculesWeapons.Herc_Ammo_AIM54C_missiles) - Herc_APC_M1043_HMMWV_Armament_Air = ( - 12, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Air, - ) - Herc_APC_M1043_HMMWV_Armament_Skid = ( - 12, - HerculesWeapons.Herc_APC_M1043_HMMWV_Armament_Skid, - ) - Herc_ATGM_M1045_HMMWV_TOW_Air = ( - 12, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Air, - ) - Herc_ATGM_M1045_HMMWV_TOW_Skid = ( - 12, - HerculesWeapons.Herc_ATGM_M1045_HMMWV_TOW_Skid, - ) - Herc_AAA_Vulcan_M163_Air = (12, HerculesWeapons.Herc_AAA_Vulcan_M163_Air) - Herc_AAA_Vulcan_M163_Skid = (12, HerculesWeapons.Herc_AAA_Vulcan_M163_Skid) - Herc_APC_LAV_25_Air = (12, HerculesWeapons.Herc_APC_LAV_25_Air) - Herc_APC_LAV_25_Skid = (12, HerculesWeapons.Herc_APC_LAV_25_Skid) - Herc_APC_M1025_HMMWV_Air = (12, HerculesWeapons.Herc_APC_M1025_HMMWV_Air) - Herc_APC_M1025_HMMWV_Skid = (12, HerculesWeapons.Herc_APC_M1025_HMMWV_Skid) - Herc_SAM_M1097_HMMWV_Air = (12, HerculesWeapons.Herc_SAM_M1097_HMMWV_Air) - Herc_SAM_M1097_HMMWV_Skid = (12, HerculesWeapons.Herc_SAM_M1097_HMMWV_Skid) - Herc_APC_COBRA_Air = (12, HerculesWeapons.Herc_APC_COBRA_Air) - Herc_APC_COBRA_Skid = (12, HerculesWeapons.Herc_APC_COBRA_Skid) - Herc_APC_M113_Air = (12, HerculesWeapons.Herc_APC_M113_Air) - Herc_APC_M113_Skid = (12, HerculesWeapons.Herc_APC_M113_Skid) - Herc_IFV_BMP_1 = (12, HerculesWeapons.Herc_IFV_BMP_1) - Herc_ARV_BRDM_2_Air = (12, HerculesWeapons.Herc_ARV_BRDM_2_Air) - Herc_ARV_BRDM_2_Skid = (12, HerculesWeapons.Herc_ARV_BRDM_2_Skid) - Herc_APC_BTR_80_Air = (12, HerculesWeapons.Herc_APC_BTR_80_Air) - Herc_APC_BTR_80_Skid = (12, HerculesWeapons.Herc_APC_BTR_80_Skid) - Herc_SAM_13 = (12, HerculesWeapons.Herc_SAM_13) - Herc_UAZ_469_Air = (12, HerculesWeapons.Herc_UAZ_469_Air) - Herc_UAZ_469_Skid = (12, HerculesWeapons.Herc_UAZ_469_Skid) - Herc_M_818 = (12, HerculesWeapons.Herc_M_818) - Herc_TIGR_233036_Air = (12, HerculesWeapons.Herc_TIGR_233036_Air) - Herc_TIGR_233036_Skid = (12, HerculesWeapons.Herc_TIGR_233036_Skid) - Herc_SAM_CHAPARRAL_Air = (12, HerculesWeapons.Herc_SAM_CHAPARRAL_Air) - Herc_SAM_CHAPARRAL_Skid = (12, HerculesWeapons.Herc_SAM_CHAPARRAL_Skid) - Herc_IFV_BMD1_Air = (12, HerculesWeapons.Herc_IFV_BMD1_Air) - Herc_IFV_BMD1_Skid = (12, HerculesWeapons.Herc_IFV_BMD1_Skid) - Herc_IFV_BTRD_Air = (12, HerculesWeapons.Herc_IFV_BTRD_Air) - Herc_IFV_BTRD_Skid = (12, HerculesWeapons.Herc_IFV_BTRD_Skid) - Herc_ART_NONA_Air = (12, HerculesWeapons.Herc_ART_NONA_Air) - Herc_ART_NONA_Skid = (12, HerculesWeapons.Herc_ART_NONA_Skid) - Herc_GEN_CRATE = (12, HerculesWeapons.Herc_GEN_CRATE) - Herc_EWR_SBORKA_Air = (12, HerculesWeapons.Herc_EWR_SBORKA_Air) - Herc_EWR_SBORKA_Skid = (12, HerculesWeapons.Herc_EWR_SBORKA_Skid) - Herc_APC_BTR_82A_Air = (12, HerculesWeapons.Herc_APC_BTR_82A_Air) - Herc_APC_BTR_82A_Skid = (12, HerculesWeapons.Herc_APC_BTR_82A_Skid) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - - tasks = [task.Transport, task.CAS, task.GroundAttack] - task_default = task.Transport diff --git a/pydcs_extensions/highdigitsams/__init__.py b/pydcs_extensions/highdigitsams/__init__.py deleted file mode 100644 index eac055455..000000000 --- a/pydcs_extensions/highdigitsams/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .highdigitsams import * diff --git a/pydcs_extensions/highdigitsams/highdigitsams.py b/pydcs_extensions/highdigitsams/highdigitsams.py deleted file mode 100644 index cf0202569..000000000 --- a/pydcs_extensions/highdigitsams/highdigitsams.py +++ /dev/null @@ -1,381 +0,0 @@ -from dcs import unittype - -from game.modsupport import vehiclemod - - -@vehiclemod -class AAA_SON_9_Fire_Can(unittype.VehicleType): - id = "Fire Can radar" - name = "AAA SON-9 Fire Can" - detection_range = 35000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class AAA_100mm_KS_19(unittype.VehicleType): - id = "KS19" - name = "AAA 100mm KS-19" - detection_range = 0 - threat_range = 15000 - air_weapon_dist = 15000 - - -@vehiclemod -class SAM_SA_10B_S_300PS_54K6_CP(unittype.VehicleType): - id = "S-300PS SA-10B 54K6 cp" - name = "SAM SA-10B S-300PS 54K6 CP" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_10B_S_300PS_5P85SE_LN(unittype.VehicleType): - id = "S-300PS 5P85SE_mod ln" - name = "SAM SA-10B S-300PS 5P85SE LN " - detection_range = 0 - threat_range = 75000 - air_weapon_dist = 75000 - - -@vehiclemod -class SAM_SA_10B_S_300PS_5P85SU_LN(unittype.VehicleType): - id = "S-300PS 5P85SU_mod ln" - name = "SAM SA-10B S-300PS 5P85SU LN " - detection_range = 0 - threat_range = 75000 - air_weapon_dist = 75000 - - -@vehiclemod -class SAM_SA_10__5V55RUD__S_300PS_LN_5P85CE(unittype.VehicleType): - id = "S-300PS 5P85CE ln" - name = "SAM SA-10 (5V55RUD) S-300PS LN 5P85CE" - detection_range = 0 - threat_range = 90000 - air_weapon_dist = 90000 - - -@vehiclemod -class SAM_SA_10__5V55RUD__S_300PS_LN_5P85DE(unittype.VehicleType): - id = "S-300PS 5P85DE ln" - name = "SAM SA-10 (5V55RUD) S-300PS LN 5P85DE" - detection_range = 0 - threat_range = 90000 - air_weapon_dist = 90000 - - -@vehiclemod -class SAM_SA_10B_S_300PS_30N6_TR(unittype.VehicleType): - id = "S-300PS 30N6 TRAILER tr" - name = "SAM SA-10B S-300PS 30N6 TR" - detection_range = 160000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_10B_S_300PS_40B6M_TR(unittype.VehicleType): - id = "S-300PS SA-10B 40B6M MAST tr" - name = "SAM SA-10B S-300PS 40B6M TR" - detection_range = 160000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_10B_S_300PS_40B6MD_SR(unittype.VehicleType): - id = "S-300PS SA-10B 40B6MD MAST sr" - name = "SAM SA-10B S-300PS 40B6MD SR" - detection_range = 60000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_10B_S_300PS_64H6E_SR(unittype.VehicleType): - id = "S-300PS 64H6E TRAILER sr" - name = "SAM SA-10B S-300PS 64H6E SR" - detection_range = 160000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_CP_54K6(unittype.VehicleType): - id = "S-300PMU1 54K6 cp" - name = "SAM SA-20 S-300PMU1 CP 54K6" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_TR_30N6E(unittype.VehicleType): - id = "S-300PMU1 40B6M tr" - name = "SAM SA-20 S-300PMU1 TR 30N6E" - detection_range = 160000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_TR_30N6E_truck(unittype.VehicleType): - id = "S-300PMU1 30N6E tr" - name = "SAM SA-20 S-300PMU1 TR 30N6E(truck)" - detection_range = 160000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_SR_5N66E(unittype.VehicleType): - id = "S-300PMU1 40B6MD sr" - name = "SAM SA-20 S-300PMU1 SR 5N66E" - detection_range = 120000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_SR_64N6E(unittype.VehicleType): - id = "S-300PMU1 64N6E sr" - name = "SAM SA-20 S-300PMU1 SR 64N6E" - detection_range = 300000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_LN_5P85CE(unittype.VehicleType): - id = "S-300PMU1 5P85CE ln" - name = "SAM SA-20 S-300PMU1 LN 5P85CE" - detection_range = 0 - threat_range = 150000 - air_weapon_dist = 150000 - - -@vehiclemod -class SAM_SA_20_S_300PMU1_LN_5P85DE(unittype.VehicleType): - id = "S-300PMU1 5P85DE ln" - name = "SAM SA-20 S-300PMU1 LN 5P85DE" - detection_range = 0 - threat_range = 150000 - air_weapon_dist = 150000 - - -@vehiclemod -class SAM_SA_20B_S_300PMU2_CP_54K6E2(unittype.VehicleType): - id = "S-300PMU2 54K6E2 cp" - name = "SAM SA-20B S-300PMU2 CP 54K6E2" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20B_S_300PMU2_TR_92H6E_truck(unittype.VehicleType): - id = "S-300PMU2 92H6E tr" - name = "SAM SA-20B S-300PMU2 TR 92H6E(truck)" - detection_range = 270000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20B_S_300PMU2_SR_64N6E2(unittype.VehicleType): - id = "S-300PMU2 64H6E2 sr" - name = "SAM SA-20B S-300PMU2 SR 64N6E2" - detection_range = 330000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_20B_S_300PMU2_LN_5P85SE2(unittype.VehicleType): - id = "S-300PMU2 5P85SE2 ln" - name = "SAM SA-20B S-300PMU2 LN 5P85SE2" - detection_range = 0 - threat_range = 200000 - air_weapon_dist = 200000 - - -@vehiclemod -class SAM_SA_12_S_300V_9S457_CP(unittype.VehicleType): - id = "S-300V 9S457 cp" - name = "SAM SA-12 S-300V 9S457 CP" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_12_S_300V_9A82_LN(unittype.VehicleType): - id = "S-300V 9A82 ln" - name = "SAM SA-12 S-300V 9A82 LN" - detection_range = 0 - threat_range = 100000 - air_weapon_dist = 100000 - - -@vehiclemod -class SAM_SA_12_S_300V_9A83_LN(unittype.VehicleType): - id = "S-300V 9A83 ln" - name = "SAM SA-12 S-300V 9A83 LN" - detection_range = 0 - threat_range = 75000 - air_weapon_dist = 75000 - - -@vehiclemod -class SAM_SA_12_S_300V_9S15_SR(unittype.VehicleType): - id = "S-300V 9S15 sr" - name = "SAM SA-12 S-300V 9S15 SR" - detection_range = 240000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_12_S_300V_9S19_SR(unittype.VehicleType): - id = "S-300V 9S19 sr" - name = "SAM SA-12 S-300V 9S19 SR" - detection_range = 175000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_12_S_300V_9S32_TR(unittype.VehicleType): - id = "S-300V 9S32 tr" - name = "SAM SA-12 S-300V 9S32 TR" - detection_range = 150000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_23_S_300VM_9S457ME_CP(unittype.VehicleType): - id = "S-300VM 9S457ME cp" - name = "SAM SA-23 S-300VM 9S457ME CP" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_23_S_300VM_9S15M2_SR(unittype.VehicleType): - id = "S-300VM 9S15M2 sr" - name = "SAM SA-23 S-300VM 9S15M2 SR" - detection_range = 320000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_23_S_300VM_9S19M2_SR(unittype.VehicleType): - id = "S-300VM 9S19M2 sr" - name = "SAM SA-23 S-300VM 9S19M2 SR" - detection_range = 310000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_23_S_300VM_9S32ME_TR(unittype.VehicleType): - id = "S-300VM 9S32ME tr" - name = "SAM SA-23 S-300VM 9S32ME TR" - detection_range = 230000 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class SAM_SA_23_S_300VM_9A83ME_LN(unittype.VehicleType): - id = "S-300VM 9A83ME ln" - name = "SAM SA-23 S-300VM 9A83ME LN" - detection_range = 0 - threat_range = 90000 - air_weapon_dist = 90000 - - -@vehiclemod -class SAM_SA_23_S_300VM_9A82ME_LN(unittype.VehicleType): - id = "S-300VM 9A82ME ln" - name = "SAM SA-23 S-300VM 9A82ME LN" - detection_range = 0 - threat_range = 200000 - air_weapon_dist = 200000 - - -@vehiclemod -class SAM_SA_17_Buk_M1_2_LN_9A310M1_2(unittype.VehicleType): - id = "SA-17 Buk M1-2 LN 9A310M1-2" - name = "SAM SA-17 Buk M1-2 LN 9A310M1-2" - detection_range = 120000 - threat_range = 50000 - air_weapon_dist = 50000 - - -@vehiclemod -class SAM_SA_2__V759__LN_SM_90(unittype.VehicleType): - id = "S_75M_Volhov_V759" - name = "SAM SA-2 (V759) LN SM-90" - detection_range = 0 - threat_range = 50000 - air_weapon_dist = 50000 - - -@vehiclemod -class SAM_HQ_2_LN_SM_90(unittype.VehicleType): - id = "HQ_2_Guideline_LN" - name = "SAM HQ-2 LN SM-90" - detection_range = 0 - threat_range = 50000 - air_weapon_dist = 50000 - - -@vehiclemod -class SAM_SA_3__V_601P__LN_5P73(unittype.VehicleType): - id = "5p73 V-601P ln" - name = "SAM SA-3 (V-601P) LN 5P73" - detection_range = 0 - threat_range = 18000 - air_weapon_dist = 18000 - - -@vehiclemod -class SAM_SA_24_Igla_S_manpad(unittype.VehicleType): - id = "SA-24 Igla-S manpad" - name = "SAM SA-24 Igla-S manpad" - detection_range = 5000 - threat_range = 6000 - air_weapon_dist = 6000 - - -@vehiclemod -class SAM_SA_14_Strela_3_manpad(unittype.VehicleType): - id = "SA-14 Strela-3 manpad" - name = "SAM SA-14 Strela-3 manpad" - detection_range = 5000 - threat_range = 4500 - air_weapon_dist = 4500 - - -@vehiclemod -class Polyana_D4M1_C2_node(unittype.VehicleType): - id = "polyana-d4m1 cp" - name = "Polyana-D4M1 C2 node" - detection_range = 0 - threat_range = 0 - air_weapon_dist = 0 - - -@vehiclemod -class _34Ya6E_Gazetchik_E_decoy(unittype.VehicleType): - id = "34Ya6E Gazetchik E decoy" - name = "34Ya6E Gazetchik E decoy" - detection_range = 20000 - threat_range = 0 - air_weapon_dist = 0 diff --git a/pydcs_extensions/jas39/__init__.py b/pydcs_extensions/jas39/__init__.py deleted file mode 100644 index 1dc77a4f5..000000000 --- a/pydcs_extensions/jas39/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .jas39 import * diff --git a/pydcs_extensions/jas39/jas39.py b/pydcs_extensions/jas39/jas39.py deleted file mode 100644 index 2a5c17ce9..000000000 --- a/pydcs_extensions/jas39/jas39.py +++ /dev/null @@ -1,999 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class JAS39GripenWeapons: - EWS_39_Integrated_ECM = { - "clsid": "{JAS39_EWS39}", - "name": "EWS 39 Integrated ECM", - "weight": 1, - } - Integrated_ELINT = { - "clsid": "{JAS39_ELINT}", - "name": "Integrated ELINT", - "weight": 1, - } - AIM_120B_AMRAAM_Active_Rdr_AAM = { - "clsid": "{JAS39_AIM120B}", - "name": "AIM-120B AMRAAM Active Rdr AAM", - "weight": 157, - } - AIM_120C_5_AMRAAM_Active_Rdr_AAM = { - "clsid": "{JAS39_AIM120C5}", - "name": "AIM-120C-5 AMRAAM Active Rdr AAM", - "weight": 162.5, - } - AIM_120C_7_AMRAAM_Active_Rdr_AAM = { - "clsid": "{JAS39_AIM120C7}", - "name": "AIM-120C-7 AMRAAM Active Rdr AAM", - "weight": 162.5, - } - AIM_9L_Sidewinder_IR_AAM_ = { - "clsid": "{JAS39_AIM-9L}", - "name": "AIM-9L Sidewinder IR AAM", - "weight": 86, - } - AIM_9M_Sidewinder_IR_AAM_ = { - "clsid": "{JAS39_AIM-9M}", - "name": "AIM-9M Sidewinder IR AAM", - "weight": 86, - } - AIM_9X_Sidewinder_IR_AAM_ = { - "clsid": "{JAS39_AIM-9X}", - "name": "AIM-9X Sidewinder IR AAM", - "weight": 86.5, - } - AIM_132_ASRAAM_IR_AAM = { - "clsid": "{JAS39_ASRAAM}", - "name": "AIM-132 ASRAAM IR AAM", - "weight": 89, - } - A_Darter_IR_AAM = { - "clsid": "{JAS39_A-DARTER}", - "name": "A-Darter IR AAM", - "weight": 90, - } - _3_x_Brimstone_Laser_Guided_Missile = { - "clsid": "{JAS39_BRIMSTONE}", - "name": "3 x Brimstone Laser Guided Missile", - "weight": 195.5, - } - I_Derby_ER_BVRAAM_Active_Rdr_AAM = { - "clsid": "{JAS39_Derby}", - "name": "I-Derby ER BVRAAM Active Rdr AAM", - "weight": 119, - } - DWS_39_MJ2_Anti_radiation_Cluster_Bomb = { - "clsid": "{JAS39_DWS39_ARM}", - "name": "DWS 39 MJ2 Anti-radiation Cluster Bomb", - "weight": 672, - } - DWS_39_MJ2_TV_Guided_Cluster_Bomb = { - "clsid": "{JAS39_DWS39_TV}", - "name": "DWS 39 MJ2 TV Guided Cluster Bomb", - "weight": 672, - } - GBU_10_2000_lb_Laser_guided_Bomb = { - "clsid": "{JAS39_GBU10}", - "name": "GBU-10 2000 lb Laser-guided Bomb", - "weight": 934, - } - GBU_12_500_lb_Laser_guided_Bomb = { - "clsid": "{JAS39_GBU12}", - "name": "GBU-12 500 lb Laser-guided Bomb", - "weight": 275, - } - GBU_16_1000_lb_Laser_guided_Bomb = { - "clsid": "{JAS39_GBU16}", - "name": "GBU-16 1000 lb Laser-guided Bomb", - "weight": 454, - } - GBU_31_2000_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_GBU31}", - "name": "GBU-31 2000 lb TV Guided Glide-Bomb", - "weight": 934, - } - GBU_31_2000_lb_Penetrator_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_GBU31_BLU109}", - "name": "GBU-31 2000 lb Penetrator TV Guided Glide-Bomb", - "weight": 970, - } - GBU_32_1000_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_GBU32}", - "name": "GBU-32 1000 lb TV Guided Glide-Bomb", - "weight": 467, - } - GBU_38_500_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_GBU38}", - "name": "GBU-38 500 lb TV Guided Glide-Bomb", - "weight": 241, - } - GBU_49_500_lb_TV_Guided_Bomb = { - "clsid": "{JAS39_GBU49}", - "name": "GBU-49 500 lb TV Guided Bomb", - "weight": 241, - } - IRIS_T_IR_AAM = {"clsid": "{JAS39_IRIS-T}", "name": "IRIS-T IR AAM", "weight": 88.4} - Litening_III_Targeting_Pod = { - "clsid": "{JAS39_Litening}", - "name": "Litening III Targeting Pod", - "weight": 208, - } - M70B_AP_Unguided_rocket = { - "clsid": "{JAS39_M70BAP}", - "name": "M70B AP Unguided rocket", - "weight": 372.2, - } - M70B_HE_Unguided_rocket = { - "clsid": "{JAS39_M70BHE}", - "name": "M70B HE Unguided rocket", - "weight": 372.2, - } - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = { - "clsid": "{JAS39_M71LD}", - "name": "4 x M/71 120 kg GP Bomb Low-drag ", - "weight": 605, - } - MAR_1_High_Speed_Anti_Radiation_Missile = { - "clsid": "{JAS39_MAR-1}", - "name": "MAR-1 High Speed Anti-Radiation Missile", - "weight": 350, - } - Meteor_BVRAAM_Active_Rdr_AAM = { - "clsid": "{JAS39_Meteor}", - "name": "Meteor BVRAAM Active Rdr AAM", - "weight": 191, - } - Python_5_IR_AAM = { - "clsid": "{JAS39_PYTHON-5}", - "name": "Python-5 IR AAM", - "weight": 106, - } - RBS_15_Mk4_Gungnir_Anti_ship_Missile = { - "clsid": "{JAS39_RBS15}", - "name": "RBS-15 Mk4 Gungnir Anti-ship Missile", - "weight": 650, - } - RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_ = { - "clsid": "{JAS39_RBS15AI}", - "name": "RBS-15 Mk4 Gungnir Anti-ship Missile (AI)", - "weight": 650, - } - _4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_SDB}", - "name": "4 x GBU-39 SDB 285 lb TV Guided Glide-Bomb", - "weight": 661, - } - Storm_Shadow_Long_Range_Anti_Radiation_Cruise_missile = { - "clsid": "{JAS39_STORMSHADOW_ARM}", - "name": "Storm Shadow Long Range Anti-Radiation Cruise-missile", - "weight": 1300, - } - Drop_tank_1100_litre = { - "clsid": "{JAS39_TANK1100}", - "name": "Drop tank 1100 litre", - "weight": 946.06, - } - Litening_III_Targeting_Pod_FLIR = { - "clsid": "{JAS39_FLIR}", - "name": "Litening III Targeting Pod FLIR", - "weight": 2, - } - Mk_82_500_lb_GP_Bomb = { - "clsid": "{JAS39_MK82}", - "name": "Mk-82 500 lb GP Bomb", - "weight": 241, - } - Mk_83_1000_lb_GP_Bomb = { - "clsid": "{JAS39_MK83}", - "name": "Mk-83 1000 lb GP Bomb", - "weight": 447, - } - Mk_84_2000_lb_GP_Bomb = { - "clsid": "{JAS39_MK84}", - "name": "Mk-84 2000 lb GP Bomb", - "weight": 894, - } - _2_x_GBU_12_500_lb_Laser_guided_Bomb = { - "clsid": "{JAS39_BRU33_GBU12}", - "name": "2 x GBU-12 500 lb Laser-guided Bomb", - "weight": 625, - } - _2_x_GBU_16_1000_lb_Laser_guided_Bomb = { - "clsid": "{JAS39_BRU33_GBU16}", - "name": "2 x GBU-16 1000 lb Laser-guided Bomb", - "weight": 983, - } - _2_x_GBU_32_1000_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_BRU33_GBU32}", - "name": "2 x GBU-32 1000 lb TV Guided Glide-Bomb", - "weight": 1009, - } - _2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb = { - "clsid": "{JAS39_BRU33_GBU38}", - "name": "2 x GBU-38 500 lb TV Guided Glide-Bomb", - "weight": 557, - } - _2_x_GBU_49_500_lb_TV_Guided_Bomb = { - "clsid": "{JAS39_BRU33_GBU49}", - "name": "2 x GBU-49 500 lb TV Guided Bomb", - "weight": 557, - } - _2_x_Mk_82_500_lb_GP_Bomb = { - "clsid": "{JAS39_BRU33_MK82}", - "name": "2 x Mk-82 500 lb GP Bomb", - "weight": 557, - } - _2_x_Mk_83_1000_lb_GP_Bomb = { - "clsid": "{JAS39_BRU33_MK83}", - "name": "2 x Mk-83 1000 lb GP Bomb", - "weight": 969, - } - _3_x_SPEAR_3_Anti_Radiation_Missile = { - "clsid": "{JAS39_SPEAR3}", - "name": "3 x SPEAR-3 Anti-Radiation Missile", - "weight": 360, - } - _3_x_SPEAR_EW_Decoy = { - "clsid": "{JAS39_SPEAREW}", - "name": "3 x SPEAR-EW Decoy", - "weight": 360, - } - KEPD_350_Long_Range_Anti_Radiation_Cruise_missile = { - "clsid": "{JAS39_KEPD350_ARM}", - "name": "KEPD 350 Long Range Anti-Radiation Cruise-missile", - "weight": 1400, - } - - -inject_weapons(JAS39GripenWeapons) - - -@planemod -class JAS39Gripen(PlaneType): - id = "JAS39Gripen" - flyable = True - height = 4.5 - width = 8.4 - length = 14.1 - fuel_max = 2550 - max_speed = 2649.996 - chaff = 80 - flare = 40 - charge_total = 120 - chaff_charge_size = 1 - flare_charge_size = 1 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - livery_name = "JAS39GRIPEN" # from type - - class Pylon1: - IRIS_T_IR_AAM = (1, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (1, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (1, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (1, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - Smokewinder___red = (1, Weapons.Smokewinder___red) - Smokewinder___green = (1, Weapons.Smokewinder___green) - Smokewinder___blue = (1, Weapons.Smokewinder___blue) - Smokewinder___white = (1, Weapons.Smokewinder___white) - Smokewinder___yellow = (1, Weapons.Smokewinder___yellow) - Smokewinder___orange = (1, Weapons.Smokewinder___orange) - - class Pylon2: - IRIS_T_IR_AAM = (2, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (2, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (2, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (2, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - Meteor_BVRAAM_Active_Rdr_AAM = ( - 2, - JAS39GripenWeapons.Meteor_BVRAAM_Active_Rdr_AAM, - ) - AIM_120B_AMRAAM_Active_Rdr_AAM = ( - 2, - JAS39GripenWeapons.AIM_120B_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_5_AMRAAM_Active_Rdr_AAM = ( - 2, - JAS39GripenWeapons.AIM_120C_5_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_7_AMRAAM_Active_Rdr_AAM = ( - 2, - JAS39GripenWeapons.AIM_120C_7_AMRAAM_Active_Rdr_AAM, - ) - I_Derby_ER_BVRAAM_Active_Rdr_AAM = ( - 2, - JAS39GripenWeapons.I_Derby_ER_BVRAAM_Active_Rdr_AAM, - ) - Mk_82_500_lb_GP_Bomb = (2, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (2, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (2, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 2, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (2, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (2, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - - class Pylon3: - AIM_9L_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - IRIS_T_IR_AAM = (3, JAS39GripenWeapons.IRIS_T_IR_AAM) - A_Darter_IR_AAM = (3, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (3, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (3, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - Meteor_BVRAAM_Active_Rdr_AAM = ( - 3, - JAS39GripenWeapons.Meteor_BVRAAM_Active_Rdr_AAM, - ) - AIM_120B_AMRAAM_Active_Rdr_AAM = ( - 3, - JAS39GripenWeapons.AIM_120B_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_5_AMRAAM_Active_Rdr_AAM = ( - 3, - JAS39GripenWeapons.AIM_120C_5_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_7_AMRAAM_Active_Rdr_AAM = ( - 3, - JAS39GripenWeapons.AIM_120C_7_AMRAAM_Active_Rdr_AAM, - ) - I_Derby_ER_BVRAAM_Active_Rdr_AAM = ( - 3, - JAS39GripenWeapons.I_Derby_ER_BVRAAM_Active_Rdr_AAM, - ) - Mk_82_500_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - Mk_84_2000_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_84_2000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (3, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _2_x_Mk_83_1000_lb_GP_Bomb = (3, JAS39GripenWeapons._2_x_Mk_83_1000_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 3, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (3, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (3, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - Drop_tank_1100_litre = (3, JAS39GripenWeapons.Drop_tank_1100_litre) - - class Pylon4: - Drop_tank_1100_litre = (4, JAS39GripenWeapons.Drop_tank_1100_litre) - - class Pylon5: - Litening_III_Targeting_Pod = (5, JAS39GripenWeapons.Litening_III_Targeting_Pod) - - class Pylon6: - AIM_9L_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - IRIS_T_IR_AAM = (6, JAS39GripenWeapons.IRIS_T_IR_AAM) - A_Darter_IR_AAM = (6, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (6, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (6, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - Meteor_BVRAAM_Active_Rdr_AAM = ( - 6, - JAS39GripenWeapons.Meteor_BVRAAM_Active_Rdr_AAM, - ) - AIM_120B_AMRAAM_Active_Rdr_AAM = ( - 6, - JAS39GripenWeapons.AIM_120B_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_5_AMRAAM_Active_Rdr_AAM = ( - 6, - JAS39GripenWeapons.AIM_120C_5_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_7_AMRAAM_Active_Rdr_AAM = ( - 6, - JAS39GripenWeapons.AIM_120C_7_AMRAAM_Active_Rdr_AAM, - ) - I_Derby_ER_BVRAAM_Active_Rdr_AAM = ( - 6, - JAS39GripenWeapons.I_Derby_ER_BVRAAM_Active_Rdr_AAM, - ) - Mk_82_500_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - Mk_84_2000_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_84_2000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (6, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _2_x_Mk_83_1000_lb_GP_Bomb = (6, JAS39GripenWeapons._2_x_Mk_83_1000_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 6, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (6, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (6, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - Drop_tank_1100_litre = (6, JAS39GripenWeapons.Drop_tank_1100_litre) - - class Pylon7: - IRIS_T_IR_AAM = (7, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (7, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (7, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (7, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - Meteor_BVRAAM_Active_Rdr_AAM = ( - 7, - JAS39GripenWeapons.Meteor_BVRAAM_Active_Rdr_AAM, - ) - AIM_120B_AMRAAM_Active_Rdr_AAM = ( - 7, - JAS39GripenWeapons.AIM_120B_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_5_AMRAAM_Active_Rdr_AAM = ( - 7, - JAS39GripenWeapons.AIM_120C_5_AMRAAM_Active_Rdr_AAM, - ) - AIM_120C_7_AMRAAM_Active_Rdr_AAM = ( - 7, - JAS39GripenWeapons.AIM_120C_7_AMRAAM_Active_Rdr_AAM, - ) - I_Derby_ER_BVRAAM_Active_Rdr_AAM = ( - 7, - JAS39GripenWeapons.I_Derby_ER_BVRAAM_Active_Rdr_AAM, - ) - Mk_82_500_lb_GP_Bomb = (7, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (7, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (7, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 7, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (7, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (7, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - - class Pylon8: - IRIS_T_IR_AAM = (8, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (8, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (8, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (8, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (8, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - Smokewinder___red = (8, Weapons.Smokewinder___red) - Smokewinder___green = (8, Weapons.Smokewinder___green) - Smokewinder___blue = (8, Weapons.Smokewinder___blue) - Smokewinder___white = (8, Weapons.Smokewinder___white) - Smokewinder___yellow = (8, Weapons.Smokewinder___yellow) - Smokewinder___orange = (8, Weapons.Smokewinder___orange) - - class Pylon9: - Litening_III_Targeting_Pod_FLIR = ( - 9, - JAS39GripenWeapons.Litening_III_Targeting_Pod_FLIR, - ) - - class Pylon10: - Integrated_ELINT = (10, JAS39GripenWeapons.Integrated_ELINT) - - class Pylon11: - EWS_39_Integrated_ECM = (11, JAS39GripenWeapons.EWS_39_Integrated_ECM) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - tasks = [ - task.Intercept, - task.CAP, - task.Reconnaissance, - task.Escort, - task.FighterSweep, - ] - task_default = task.FighterSweep - - -@planemod -class JAS39Gripen_AG(PlaneType): - id = "JAS39Gripen_AG" - flyable = True - height = 4.5 - width = 8.4 - length = 14.1 - fuel_max = 2550 - max_speed = 2649.996 - chaff = 80 - flare = 40 - charge_total = 120 - chaff_charge_size = 1 - flare_charge_size = 1 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - livery_name = "JAS39GRIPEN_AG" # from type - - class Pylon1: - IRIS_T_IR_AAM = (1, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (1, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (1, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (1, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (1, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (1, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - Smokewinder___red = (1, Weapons.Smokewinder___red) - Smokewinder___green = (1, Weapons.Smokewinder___green) - Smokewinder___blue = (1, Weapons.Smokewinder___blue) - Smokewinder___white = (1, Weapons.Smokewinder___white) - Smokewinder___yellow = (1, Weapons.Smokewinder___yellow) - Smokewinder___orange = (1, Weapons.Smokewinder___orange) - - class Pylon2: - IRIS_T_IR_AAM = (2, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (2, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (2, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (2, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (2, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - RBS_15_Mk4_Gungnir_Anti_ship_Missile = ( - 2, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile, - ) - RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_ = ( - 2, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_, - ) - MAR_1_High_Speed_Anti_Radiation_Missile = ( - 2, - JAS39GripenWeapons.MAR_1_High_Speed_Anti_Radiation_Missile, - ) - GBU_49_500_lb_TV_Guided_Bomb = ( - 2, - JAS39GripenWeapons.GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 2, - JAS39GripenWeapons.GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 2, - JAS39GripenWeapons.GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb = ( - 2, - JAS39GripenWeapons._4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb, - ) - GBU_12_500_lb_Laser_guided_Bomb = ( - 2, - JAS39GripenWeapons.GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_12_500_lb_Laser_guided_Bomb = ( - 2, - JAS39GripenWeapons._2_x_GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 2, - JAS39GripenWeapons._2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _2_x_GBU_49_500_lb_TV_Guided_Bomb = ( - 2, - JAS39GripenWeapons._2_x_GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_16_1000_lb_Laser_guided_Bomb = ( - 2, - JAS39GripenWeapons.GBU_16_1000_lb_Laser_guided_Bomb, - ) - DWS_39_MJ2_TV_Guided_Cluster_Bomb = ( - 2, - JAS39GripenWeapons.DWS_39_MJ2_TV_Guided_Cluster_Bomb, - ) - DWS_39_MJ2_Anti_radiation_Cluster_Bomb = ( - 2, - JAS39GripenWeapons.DWS_39_MJ2_Anti_radiation_Cluster_Bomb, - ) - Mk_82_500_lb_GP_Bomb = (2, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (2, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (2, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 2, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (2, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (2, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - _3_x_Brimstone_Laser_Guided_Missile = ( - 2, - JAS39GripenWeapons._3_x_Brimstone_Laser_Guided_Missile, - ) - LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_ = ( - 2, - Weapons.LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_, - ) - LAU_117_AGM_65H = (2, Weapons.LAU_117_AGM_65H) - _3_x_SPEAR_3_Anti_Radiation_Missile = ( - 2, - JAS39GripenWeapons._3_x_SPEAR_3_Anti_Radiation_Missile, - ) - _3_x_SPEAR_EW_Decoy = (2, JAS39GripenWeapons._3_x_SPEAR_EW_Decoy) - - class Pylon3: - AIM_9L_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - IRIS_T_IR_AAM = (3, JAS39GripenWeapons.IRIS_T_IR_AAM) - A_Darter_IR_AAM = (3, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (3, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (3, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (3, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_ = ( - 3, - Weapons.LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_, - ) - LAU_117_AGM_65H = (3, Weapons.LAU_117_AGM_65H) - _3_x_Brimstone_Laser_Guided_Missile = ( - 3, - JAS39GripenWeapons._3_x_Brimstone_Laser_Guided_Missile, - ) - _3_x_SPEAR_3_Anti_Radiation_Missile = ( - 3, - JAS39GripenWeapons._3_x_SPEAR_3_Anti_Radiation_Missile, - ) - _3_x_SPEAR_EW_Decoy = (3, JAS39GripenWeapons._3_x_SPEAR_EW_Decoy) - RBS_15_Mk4_Gungnir_Anti_ship_Missile = ( - 3, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile, - ) - RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_ = ( - 3, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_, - ) - MAR_1_High_Speed_Anti_Radiation_Missile = ( - 3, - JAS39GripenWeapons.MAR_1_High_Speed_Anti_Radiation_Missile, - ) - GBU_49_500_lb_TV_Guided_Bomb = ( - 3, - JAS39GripenWeapons.GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_31_2000_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons.GBU_31_2000_lb_TV_Guided_Glide_Bomb, - ) - GBU_31_2000_lb_Penetrator_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons.GBU_31_2000_lb_Penetrator_TV_Guided_Glide_Bomb, - ) - GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons.GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons.GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons._4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb, - ) - GBU_12_500_lb_Laser_guided_Bomb = ( - 3, - JAS39GripenWeapons.GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_12_500_lb_Laser_guided_Bomb = ( - 3, - JAS39GripenWeapons._2_x_GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons._2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _2_x_GBU_49_500_lb_TV_Guided_Bomb = ( - 3, - JAS39GripenWeapons._2_x_GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_10_2000_lb_Laser_guided_Bomb = ( - 3, - JAS39GripenWeapons.GBU_10_2000_lb_Laser_guided_Bomb, - ) - GBU_16_1000_lb_Laser_guided_Bomb = ( - 3, - JAS39GripenWeapons.GBU_16_1000_lb_Laser_guided_Bomb, - ) - _2_x_GBU_16_1000_lb_Laser_guided_Bomb = ( - 3, - JAS39GripenWeapons._2_x_GBU_16_1000_lb_Laser_guided_Bomb, - ) - _2_x_GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 3, - JAS39GripenWeapons._2_x_GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - DWS_39_MJ2_TV_Guided_Cluster_Bomb = ( - 3, - JAS39GripenWeapons.DWS_39_MJ2_TV_Guided_Cluster_Bomb, - ) - DWS_39_MJ2_Anti_radiation_Cluster_Bomb = ( - 3, - JAS39GripenWeapons.DWS_39_MJ2_Anti_radiation_Cluster_Bomb, - ) - Mk_82_500_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - Mk_84_2000_lb_GP_Bomb = (3, JAS39GripenWeapons.Mk_84_2000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (3, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _2_x_Mk_83_1000_lb_GP_Bomb = (3, JAS39GripenWeapons._2_x_Mk_83_1000_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 3, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - Drop_tank_1100_litre = (3, JAS39GripenWeapons.Drop_tank_1100_litre) - M70B_HE_Unguided_rocket = (3, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (3, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - Storm_Shadow_Long_Range_Anti_Radiation_Cruise_missile = ( - 3, - JAS39GripenWeapons.Storm_Shadow_Long_Range_Anti_Radiation_Cruise_missile, - ) - KEPD_350_Long_Range_Anti_Radiation_Cruise_missile = ( - 3, - JAS39GripenWeapons.KEPD_350_Long_Range_Anti_Radiation_Cruise_missile, - ) - - class Pylon4: - Drop_tank_1100_litre = (4, JAS39GripenWeapons.Drop_tank_1100_litre) - - # ERRR {INV-SMOKE-RED} - # ERRR {INV-SMOKE-GREEN} - # ERRR {INV-SMOKE-BLUE} - # ERRR {INV-SMOKE-WHITE} - # ERRR {INV-SMOKE-YELLOW} - # ERRR {INV-SMOKE-ORANGE} - - class Pylon5: - Litening_III_Targeting_Pod = (5, JAS39GripenWeapons.Litening_III_Targeting_Pod) - - class Pylon6: - AIM_9L_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - IRIS_T_IR_AAM = (6, JAS39GripenWeapons.IRIS_T_IR_AAM) - A_Darter_IR_AAM = (6, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (6, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (6, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (6, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_ = ( - 6, - Weapons.LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_, - ) - LAU_117_AGM_65H = (6, Weapons.LAU_117_AGM_65H) - _3_x_Brimstone_Laser_Guided_Missile = ( - 6, - JAS39GripenWeapons._3_x_Brimstone_Laser_Guided_Missile, - ) - _3_x_SPEAR_3_Anti_Radiation_Missile = ( - 6, - JAS39GripenWeapons._3_x_SPEAR_3_Anti_Radiation_Missile, - ) - _3_x_SPEAR_EW_Decoy = (6, JAS39GripenWeapons._3_x_SPEAR_EW_Decoy) - RBS_15_Mk4_Gungnir_Anti_ship_Missile = ( - 6, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile, - ) - RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_ = ( - 6, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_, - ) - MAR_1_High_Speed_Anti_Radiation_Missile = ( - 6, - JAS39GripenWeapons.MAR_1_High_Speed_Anti_Radiation_Missile, - ) - GBU_49_500_lb_TV_Guided_Bomb = ( - 6, - JAS39GripenWeapons.GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_31_2000_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons.GBU_31_2000_lb_TV_Guided_Glide_Bomb, - ) - GBU_31_2000_lb_Penetrator_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons.GBU_31_2000_lb_Penetrator_TV_Guided_Glide_Bomb, - ) - GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons.GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons.GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons._4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb, - ) - GBU_12_500_lb_Laser_guided_Bomb = ( - 6, - JAS39GripenWeapons.GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_12_500_lb_Laser_guided_Bomb = ( - 6, - JAS39GripenWeapons._2_x_GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons._2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _2_x_GBU_49_500_lb_TV_Guided_Bomb = ( - 6, - JAS39GripenWeapons._2_x_GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_10_2000_lb_Laser_guided_Bomb = ( - 6, - JAS39GripenWeapons.GBU_10_2000_lb_Laser_guided_Bomb, - ) - GBU_16_1000_lb_Laser_guided_Bomb = ( - 6, - JAS39GripenWeapons.GBU_16_1000_lb_Laser_guided_Bomb, - ) - _2_x_GBU_16_1000_lb_Laser_guided_Bomb = ( - 6, - JAS39GripenWeapons._2_x_GBU_16_1000_lb_Laser_guided_Bomb, - ) - _2_x_GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 6, - JAS39GripenWeapons._2_x_GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - DWS_39_MJ2_TV_Guided_Cluster_Bomb = ( - 6, - JAS39GripenWeapons.DWS_39_MJ2_TV_Guided_Cluster_Bomb, - ) - DWS_39_MJ2_Anti_radiation_Cluster_Bomb = ( - 6, - JAS39GripenWeapons.DWS_39_MJ2_Anti_radiation_Cluster_Bomb, - ) - Mk_82_500_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - Mk_84_2000_lb_GP_Bomb = (6, JAS39GripenWeapons.Mk_84_2000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (6, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _2_x_Mk_83_1000_lb_GP_Bomb = (6, JAS39GripenWeapons._2_x_Mk_83_1000_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 6, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - Drop_tank_1100_litre = (6, JAS39GripenWeapons.Drop_tank_1100_litre) - M70B_HE_Unguided_rocket = (6, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (6, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - Storm_Shadow_Long_Range_Anti_Radiation_Cruise_missile = ( - 6, - JAS39GripenWeapons.Storm_Shadow_Long_Range_Anti_Radiation_Cruise_missile, - ) - KEPD_350_Long_Range_Anti_Radiation_Cruise_missile = ( - 6, - JAS39GripenWeapons.KEPD_350_Long_Range_Anti_Radiation_Cruise_missile, - ) - - class Pylon7: - IRIS_T_IR_AAM = (7, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (7, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (7, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (7, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (7, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - RBS_15_Mk4_Gungnir_Anti_ship_Missile = ( - 7, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile, - ) - RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_ = ( - 7, - JAS39GripenWeapons.RBS_15_Mk4_Gungnir_Anti_ship_Missile__AI_, - ) - MAR_1_High_Speed_Anti_Radiation_Missile = ( - 7, - JAS39GripenWeapons.MAR_1_High_Speed_Anti_Radiation_Missile, - ) - GBU_49_500_lb_TV_Guided_Bomb = ( - 7, - JAS39GripenWeapons.GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_32_1000_lb_TV_Guided_Glide_Bomb = ( - 7, - JAS39GripenWeapons.GBU_32_1000_lb_TV_Guided_Glide_Bomb, - ) - GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 7, - JAS39GripenWeapons.GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb = ( - 7, - JAS39GripenWeapons._4_x_GBU_39_SDB_285_lb_TV_Guided_Glide_Bomb, - ) - GBU_12_500_lb_Laser_guided_Bomb = ( - 7, - JAS39GripenWeapons.GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_12_500_lb_Laser_guided_Bomb = ( - 7, - JAS39GripenWeapons._2_x_GBU_12_500_lb_Laser_guided_Bomb, - ) - _2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb = ( - 7, - JAS39GripenWeapons._2_x_GBU_38_500_lb_TV_Guided_Glide_Bomb, - ) - _2_x_GBU_49_500_lb_TV_Guided_Bomb = ( - 7, - JAS39GripenWeapons._2_x_GBU_49_500_lb_TV_Guided_Bomb, - ) - GBU_16_1000_lb_Laser_guided_Bomb = ( - 7, - JAS39GripenWeapons.GBU_16_1000_lb_Laser_guided_Bomb, - ) - DWS_39_MJ2_TV_Guided_Cluster_Bomb = ( - 7, - JAS39GripenWeapons.DWS_39_MJ2_TV_Guided_Cluster_Bomb, - ) - DWS_39_MJ2_Anti_radiation_Cluster_Bomb = ( - 7, - JAS39GripenWeapons.DWS_39_MJ2_Anti_radiation_Cluster_Bomb, - ) - Mk_82_500_lb_GP_Bomb = (7, JAS39GripenWeapons.Mk_82_500_lb_GP_Bomb) - Mk_83_1000_lb_GP_Bomb = (7, JAS39GripenWeapons.Mk_83_1000_lb_GP_Bomb) - _2_x_Mk_82_500_lb_GP_Bomb = (7, JAS39GripenWeapons._2_x_Mk_82_500_lb_GP_Bomb) - _4_x_M_71_120_kg_GP_Bomb_Low_drag_ = ( - 7, - JAS39GripenWeapons._4_x_M_71_120_kg_GP_Bomb_Low_drag_, - ) - M70B_HE_Unguided_rocket = (7, JAS39GripenWeapons.M70B_HE_Unguided_rocket) - M70B_AP_Unguided_rocket = (7, JAS39GripenWeapons.M70B_AP_Unguided_rocket) - _3_x_Brimstone_Laser_Guided_Missile = ( - 7, - JAS39GripenWeapons._3_x_Brimstone_Laser_Guided_Missile, - ) - LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_ = ( - 7, - Weapons.LAU_117_with_AGM_65K___Maverick_K__CCD_Imp_ASM_, - ) - LAU_117_AGM_65H = (7, Weapons.LAU_117_AGM_65H) - _3_x_SPEAR_3_Anti_Radiation_Missile = ( - 7, - JAS39GripenWeapons._3_x_SPEAR_3_Anti_Radiation_Missile, - ) - _3_x_SPEAR_EW_Decoy = (7, JAS39GripenWeapons._3_x_SPEAR_EW_Decoy) - - class Pylon8: - IRIS_T_IR_AAM = (8, JAS39GripenWeapons.IRIS_T_IR_AAM) - AIM_9L_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9L_Sidewinder_IR_AAM_) - A_Darter_IR_AAM = (8, JAS39GripenWeapons.A_Darter_IR_AAM) - AIM_9M_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9M_Sidewinder_IR_AAM_) - AIM_9X_Sidewinder_IR_AAM_ = (8, JAS39GripenWeapons.AIM_9X_Sidewinder_IR_AAM_) - Python_5_IR_AAM = (8, JAS39GripenWeapons.Python_5_IR_AAM) - AIM_132_ASRAAM_IR_AAM = (8, JAS39GripenWeapons.AIM_132_ASRAAM_IR_AAM) - AN_ASQ_T50_TCTS_Pod___ACMI_Pod = (8, Weapons.AN_ASQ_T50_TCTS_Pod___ACMI_Pod) - Smokewinder___red = (8, Weapons.Smokewinder___red) - Smokewinder___green = (8, Weapons.Smokewinder___green) - Smokewinder___blue = (8, Weapons.Smokewinder___blue) - Smokewinder___white = (8, Weapons.Smokewinder___white) - Smokewinder___yellow = (8, Weapons.Smokewinder___yellow) - Smokewinder___orange = (8, Weapons.Smokewinder___orange) - - class Pylon9: - Litening_III_Targeting_Pod_FLIR = ( - 9, - JAS39GripenWeapons.Litening_III_Targeting_Pod_FLIR, - ) - - class Pylon10: - Integrated_ELINT = (10, JAS39GripenWeapons.Integrated_ELINT) - - class Pylon11: - EWS_39_Integrated_ECM = (11, JAS39GripenWeapons.EWS_39_Integrated_ECM) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} - - tasks = [ - task.SEAD, - task.AntishipStrike, - task.CAS, - task.GroundAttack, - task.PinpointStrike, - task.RunwayAttack, - ] - task_default = task.CAS diff --git a/pydcs_extensions/ov10a/__init__.py b/pydcs_extensions/ov10a/__init__.py deleted file mode 100644 index 883943a0a..000000000 --- a/pydcs_extensions/ov10a/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .ov10a import * diff --git a/pydcs_extensions/ov10a/ov10a.py b/pydcs_extensions/ov10a/ov10a.py deleted file mode 100644 index 0b3efca67..000000000 --- a/pydcs_extensions/ov10a/ov10a.py +++ /dev/null @@ -1,417 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsOV10A: - LAU_33A = {"clsid": "{LAU-33A}", "name": "LAU-33A", "weight": 155} - Mk4_mod_0 = {"clsid": "{MK4_Mod0_OV10}", "name": "Mk4 mod 0", "weight": 612.35} - OV10_SMOKE = {"clsid": "{OV10_SMOKE}", "name": "OV10_SMOKE", "weight": 1} - OV10_Paratrooper = { - "clsid": "OV10_Paratrooper", - "name": "OV10_Paratrooper", - "weight": 400, - } - Fuel_Tank_150_gallons_ = { - "clsid": "{150gal}", - "name": "Fuel Tank 150 gallons", - "weight": 499.5592, - } - - -inject_weapons(WeaponsOV10A) - - -@planemod -class Bronco_OV_10A(PlaneType): - id = "Bronco-OV-10A" - flyable = True - height = 4.62 - width = 12.9 - length = 12.76 - fuel_max = 940 - max_speed = 684 - eplrs = True - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - radio_frequency = 127.5 - - panel_radio = { - 1: { - "channels": {6: 41, 2: 31, 8: 50, 3: 32, 1: 30, 4: 33, 5: 40, 7: 42}, - }, - } - - livery_name = "BRONCO-OV-10A" # from type - - class Pylon1: - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 1, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 1, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_33A = (1, Weapons.LAU_33A) - - # ERRR {MK-81} - - class Pylon2: - Mk_82___500lb_GP_Bomb_LD = (2, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (2, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (2, Weapons.Mk_83___1000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (2, Weapons.M117___750lb_GP_Bomb_LD) - LAU3_WP156 = (2, Weapons.LAU3_WP156) - LAU3_WP1B = (2, Weapons.LAU3_WP1B) - LAU3_WP61 = (2, Weapons.LAU3_WP61) - LAU3_HE5 = (2, Weapons.LAU3_HE5) - LAU3_HE151 = (2, Weapons.LAU3_HE151) - M260_HYDRA = (2, Weapons.M260_HYDRA) - M260_HYDRA_WP = (2, Weapons.M260_HYDRA_WP) - LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 2, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 2, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - - # ERRR {MK-81} - - class Pylon3: - Mk_82___500lb_GP_Bomb_LD = (3, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (3, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (3, Weapons.Mk_83___1000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (3, Weapons.M117___750lb_GP_Bomb_LD) - LAU3_WP156 = (3, Weapons.LAU3_WP156) - LAU3_WP1B = (3, Weapons.LAU3_WP1B) - LAU3_WP61 = (3, Weapons.LAU3_WP61) - LAU3_HE5 = (3, Weapons.LAU3_HE5) - LAU3_HE151 = (3, Weapons.LAU3_HE151) - M260_HYDRA = (3, Weapons.M260_HYDRA) - M260_HYDRA_WP = (3, Weapons.M260_HYDRA_WP) - LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 3, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 3, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - - class Pylon4: - Fuel_Tank_150_gallons_ = (4, Weapons.Fuel_Tank_150_gallons_) - # ERRR {MK-81} - Mk_82___500lb_GP_Bomb_LD = (4, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (4, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (4, Weapons.Mk_83___1000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (4, Weapons.M117___750lb_GP_Bomb_LD) - Mk4_mod_0 = (4, Weapons.Mk4_mod_0) - - # ERRR {MK-81} - - class Pylon5: - Mk_82___500lb_GP_Bomb_LD = (5, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (5, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (5, Weapons.Mk_83___1000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (5, Weapons.M117___750lb_GP_Bomb_LD) - LAU3_WP156 = (5, Weapons.LAU3_WP156) - LAU3_WP1B = (5, Weapons.LAU3_WP1B) - LAU3_WP61 = (5, Weapons.LAU3_WP61) - LAU3_HE5 = (5, Weapons.LAU3_HE5) - LAU3_HE151 = (5, Weapons.LAU3_HE151) - M260_HYDRA = (5, Weapons.M260_HYDRA) - M260_HYDRA_WP = (5, Weapons.M260_HYDRA_WP) - LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 5, - Weapons.LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 5, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 5, - Weapons.LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 5, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 5, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - - # ERRR {MK-81} - - class Pylon6: - Mk_82___500lb_GP_Bomb_LD = (6, Weapons.Mk_82___500lb_GP_Bomb_LD) - Mk_82_Snakeye___500lb_GP_Bomb_HD = (6, Weapons.Mk_82_Snakeye___500lb_GP_Bomb_HD) - Mk_83___1000lb_GP_Bomb_LD = (6, Weapons.Mk_83___1000lb_GP_Bomb_LD) - M117___750lb_GP_Bomb_LD = (6, Weapons.M117___750lb_GP_Bomb_LD) - LAU3_WP156 = (6, Weapons.LAU3_WP156) - LAU3_WP1B = (6, Weapons.LAU3_WP1B) - LAU3_WP61 = (6, Weapons.LAU3_WP61) - LAU3_HE5 = (6, Weapons.LAU3_HE5) - LAU3_HE151 = (6, Weapons.LAU3_HE151) - M260_HYDRA = (6, Weapons.M260_HYDRA) - M260_HYDRA_WP = (6, Weapons.M260_HYDRA_WP) - LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 6, - Weapons.LAU_10R_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG = ( - 6, - Weapons.LAU_10_pod___4_x_127mm_ZUNI__UnGd_Rkts_Mk71__HE_FRAG, - ) - LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 6, - Weapons.LAU_61R_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 6, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 6, - Weapons.LAU_61_pod___19_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk1__HE, - ) - LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_FFAR__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M151__HE, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M156__Wht_Phos, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M257__Para_Illum, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_M274__Practice_Smk, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk1__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk5__HEAT, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_Mk61__Practice, - ) - LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice = ( - 6, - Weapons.LAU_68_pod___7_x_2_75_Hydra__UnGd_Rkts_WTU_1_B__Practice, - ) - - class Pylon7: - LAU_7_with_AIM_9P_Sidewinder_IR_AAM = ( - 7, - Weapons.LAU_7_with_AIM_9P_Sidewinder_IR_AAM, - ) - LAU_7_with_AIM_9B_Sidewinder_IR_AAM = ( - 7, - Weapons.LAU_7_with_AIM_9B_Sidewinder_IR_AAM, - ) - LAU_33A = (7, Weapons.LAU_33A) - - class Pylon8: - OV10_Paratrooper = (8, Weapons.OV10_Paratrooper) - - class Pylon9: - OV10_SMOKE = (9, Weapons.OV10_SMOKE) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9} - - tasks = [ - task.GroundAttack, - task.RunwayAttack, - task.PinpointStrike, - task.CAS, - task.AFAC, - task.CAP, - task.Escort, - task.FighterSweep, - task.Intercept, - ] - task_default = task.CAS diff --git a/pydcs_extensions/su57/__init__.py b/pydcs_extensions/su57/__init__.py deleted file mode 100644 index 722159c70..000000000 --- a/pydcs_extensions/su57/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .su57 import * diff --git a/pydcs_extensions/su57/su57.py b/pydcs_extensions/su57/su57.py deleted file mode 100644 index 4b1cf270b..000000000 --- a/pydcs_extensions/su57/su57.py +++ /dev/null @@ -1,544 +0,0 @@ -from typing import Set - -from dcs import task -from dcs.planes import PlaneType -from dcs.weapons_data import Weapons - -from game.modsupport import planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class Su57Weapons: - Kh_59MK2 = {"clsid": "{KH_59MK2}", "name": "Kh-59MK2", "weight": None} - RVV_AE = {"clsid": "{RVV-AE}", "name": "RVV-AE", "weight": 250} - RVV_BD = {"clsid": "{RVV-BD}", "name": "RVV-BD", "weight": 600} - RVV_L = {"clsid": "{RVV-L}", "name": "RVV-L", "weight": 748} - RVV_M = {"clsid": "{RVV-M}", "name": "RVV-M", "weight": 190} - Su_57_Fuel_Tank = { - "clsid": "{SU_57Tank}", - "name": "Su-57 Fuel Tank", - "weight": 1561.421, - } - - -inject_weapons(Su57Weapons) - - -@planemod -class Su_57(PlaneType): - id = "Su-57" - flyable = True - height = 4.074 - width = 13.95 - length = 19.008 - fuel_max = 10300 - max_speed = 2499.984 - chaff = 100 - flare = 96 - charge_total = 200 - chaff_charge_size = 1 - flare_charge_size = 1 - category = "Interceptor" # {78EFB7A2-FD52-4b57-A6A6-3BF0E1D6555F} - - livery_name = "SU-57" # from type - - class Pylon1: - R_73__AA_11_Archer____Infra_Red = (1, Weapons.R_73__AA_11_Archer____Infra_Red) - RVV_AE = (1, Su57Weapons.RVV_AE) - RVV_M = (1, Su57Weapons.RVV_M) - Smoke_Generator___red = (1, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (1, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (1, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (1, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (1, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (1, Weapons.Smoke_Generator___orange) - - class Pylon2: - R_27R__AA_10_Alamo_A____Semi_Act_Rdr = ( - 2, - Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr, - ) - R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = ( - 2, - Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range, - ) - R_27T__AA_10_Alamo_B____Infra_Red = ( - 2, - Weapons.R_27T__AA_10_Alamo_B____Infra_Red, - ) - R_27ET__AA_10_Alamo_D____IR_Extended_Range = ( - 2, - Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range, - ) - R_77__AA_12_Adder____Active_Rdr = (2, Weapons.R_77__AA_12_Adder____Active_Rdr) - R_73__AA_11_Archer____Infra_Red = (2, Weapons.R_73__AA_11_Archer____Infra_Red) - Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = ( - 2, - Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr, - ) - Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = ( - 2, - Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr, - ) - Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = ( - 2, - Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser, - ) - Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = ( - 2, - Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided, - ) - Kh_59M__AS_18_Kazoo____930kg__ASM__IN = ( - 2, - Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN, - ) - MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = ( - 2, - Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD, - ) - B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = ( - 2, - Weapons.B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag, - ) - S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = ( - 2, - Weapons.S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator, - ) - BetAB_500___500kg_Concrete_Piercing_Bomb_LD = ( - 2, - Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD, - ) - KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = ( - 2, - Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag, - ) - KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = ( - 2, - Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP, - ) - FAB_250___250kg_GP_Bomb_LD = (2, Weapons.FAB_250___250kg_GP_Bomb_LD) - RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = ( - 2, - Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP, - ) - FAB_500_M_62___500kg_GP_Bomb_LD = (2, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD) - RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = ( - 2, - Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP, - ) - KAB_500LG___500kg_Laser_Guided_Bomb = ( - 2, - Weapons.KAB_500LG___500kg_Laser_Guided_Bomb, - ) - KAB_500Kr___500kg_TV_Guided_Bomb = (2, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb) - FAB_1500_M_54___1500kg_GP_Bomb_LD = ( - 2, - Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD, - ) - KAB_1500L___1500kg_Laser_Guided_Bomb = ( - 2, - Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb, - ) - MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = ( - 2, - Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD, - ) - RVV_BD = (2, Su57Weapons.RVV_BD) - RVV_AE = (2, Su57Weapons.RVV_AE) - RVV_M = (2, Su57Weapons.RVV_M) - RVV_L = (2, Su57Weapons.RVV_L) - Fuel_tank_800L_Wing = (2, Weapons.Fuel_tank_800L_Wing) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 2, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - Su_57_Fuel_Tank = (2, Su57Weapons.Su_57_Fuel_Tank) - Kh_59MK2 = (2, Su57Weapons.Kh_59MK2) - Smoke_Generator___red = (2, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (2, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (2, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (2, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (2, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (2, Weapons.Smoke_Generator___orange) - - class Pylon3: - R_73__AA_11_Archer____Infra_Red = (3, Weapons.R_73__AA_11_Archer____Infra_Red) - Smoke_Generator___red = (3, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (3, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (3, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (3, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (3, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (3, Weapons.Smoke_Generator___orange) - - class Pylon4: - R_27R__AA_10_Alamo_A____Semi_Act_Rdr = ( - 4, - Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr, - ) - R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = ( - 4, - Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range, - ) - R_27T__AA_10_Alamo_B____Infra_Red = ( - 4, - Weapons.R_27T__AA_10_Alamo_B____Infra_Red, - ) - R_27ET__AA_10_Alamo_D____IR_Extended_Range = ( - 4, - Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range, - ) - R_77__AA_12_Adder____Active_Rdr = (4, Weapons.R_77__AA_12_Adder____Active_Rdr) - R_73__AA_11_Archer____Infra_Red = (4, Weapons.R_73__AA_11_Archer____Infra_Red) - Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = ( - 4, - Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr, - ) - Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = ( - 4, - Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr, - ) - Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = ( - 4, - Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser, - ) - Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = ( - 4, - Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided, - ) - Kh_59M__AS_18_Kazoo____930kg__ASM__IN = ( - 4, - Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN, - ) - MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = ( - 4, - Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD, - ) - B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = ( - 4, - Weapons.B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag, - ) - S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = ( - 4, - Weapons.S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator, - ) - BetAB_500___500kg_Concrete_Piercing_Bomb_LD = ( - 4, - Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD, - ) - KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = ( - 4, - Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag, - ) - KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = ( - 4, - Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP, - ) - FAB_250___250kg_GP_Bomb_LD = (4, Weapons.FAB_250___250kg_GP_Bomb_LD) - RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = ( - 4, - Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP, - ) - FAB_500_M_62___500kg_GP_Bomb_LD = (4, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD) - RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = ( - 4, - Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP, - ) - KAB_500LG___500kg_Laser_Guided_Bomb = ( - 4, - Weapons.KAB_500LG___500kg_Laser_Guided_Bomb, - ) - KAB_500Kr___500kg_TV_Guided_Bomb = (4, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb) - FAB_1500_M_54___1500kg_GP_Bomb_LD = ( - 4, - Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD, - ) - KAB_1500L___1500kg_Laser_Guided_Bomb = ( - 4, - Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb, - ) - MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = ( - 4, - Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD, - ) - RVV_BD = (4, Su57Weapons.RVV_BD) - RVV_AE = (4, Su57Weapons.RVV_AE) - RVV_M = (4, Su57Weapons.RVV_M) - RVV_L = (4, Su57Weapons.RVV_L) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 4, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - Su_57_Fuel_Tank = (4, Su57Weapons.Su_57_Fuel_Tank) - Kh_59MK2 = (4, Su57Weapons.Kh_59MK2) - - class Pylon5: - R_77__AA_12_Adder____Active_Rdr = (5, Weapons.R_77__AA_12_Adder____Active_Rdr) - RVV_AE = (5, Su57Weapons.RVV_AE) - RVV_M = (5, Su57Weapons.RVV_M) - Kh_59MK2 = (5, Su57Weapons.Kh_59MK2) - - class Pylon6: - R_77__AA_12_Adder____Active_Rdr = (6, Weapons.R_77__AA_12_Adder____Active_Rdr) - RVV_AE = (6, Su57Weapons.RVV_AE) - RVV_M = (6, Su57Weapons.RVV_M) - Kh_59MK2 = (6, Su57Weapons.Kh_59MK2) - - class Pylon7: - R_77__AA_12_Adder____Active_Rdr = (7, Weapons.R_77__AA_12_Adder____Active_Rdr) - RVV_AE = (7, Su57Weapons.RVV_AE) - RVV_M = (7, Su57Weapons.RVV_M) - Kh_59MK2 = (7, Su57Weapons.Kh_59MK2) - - class Pylon8: - R_77__AA_12_Adder____Active_Rdr = (8, Weapons.R_77__AA_12_Adder____Active_Rdr) - RVV_AE = (8, Su57Weapons.RVV_AE) - RVV_M = (8, Su57Weapons.RVV_M) - Kh_59MK2 = (8, Su57Weapons.Kh_59MK2) - - class Pylon9: - R_27R__AA_10_Alamo_A____Semi_Act_Rdr = ( - 9, - Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr, - ) - R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = ( - 9, - Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range, - ) - R_27T__AA_10_Alamo_B____Infra_Red = ( - 9, - Weapons.R_27T__AA_10_Alamo_B____Infra_Red, - ) - R_27ET__AA_10_Alamo_D____IR_Extended_Range = ( - 9, - Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range, - ) - R_77__AA_12_Adder____Active_Rdr = (9, Weapons.R_77__AA_12_Adder____Active_Rdr) - R_73__AA_11_Archer____Infra_Red = (9, Weapons.R_73__AA_11_Archer____Infra_Red) - Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = ( - 9, - Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr, - ) - Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = ( - 9, - Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr, - ) - Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = ( - 9, - Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser, - ) - Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = ( - 9, - Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided, - ) - Kh_59M__AS_18_Kazoo____930kg__ASM__IN = ( - 9, - Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN, - ) - MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = ( - 9, - Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD, - ) - B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = ( - 9, - Weapons.B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag, - ) - S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = ( - 9, - Weapons.S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator, - ) - BetAB_500___500kg_Concrete_Piercing_Bomb_LD = ( - 9, - Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD, - ) - KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = ( - 9, - Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag, - ) - KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = ( - 9, - Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP, - ) - FAB_250___250kg_GP_Bomb_LD = (9, Weapons.FAB_250___250kg_GP_Bomb_LD) - RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = ( - 9, - Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP, - ) - FAB_500_M_62___500kg_GP_Bomb_LD = (9, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD) - RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = ( - 9, - Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP, - ) - KAB_500LG___500kg_Laser_Guided_Bomb = ( - 9, - Weapons.KAB_500LG___500kg_Laser_Guided_Bomb, - ) - KAB_500Kr___500kg_TV_Guided_Bomb = (9, Weapons.KAB_500Kr___500kg_TV_Guided_Bomb) - FAB_1500_M_54___1500kg_GP_Bomb_LD = ( - 9, - Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD, - ) - KAB_1500L___1500kg_Laser_Guided_Bomb = ( - 9, - Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb, - ) - MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = ( - 9, - Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD, - ) - RVV_BD = (9, Su57Weapons.RVV_BD) - RVV_AE = (9, Su57Weapons.RVV_AE) - RVV_M = (9, Su57Weapons.RVV_M) - RVV_L = (9, Su57Weapons.RVV_L) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 9, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - Su_57_Fuel_Tank = (9, Su57Weapons.Su_57_Fuel_Tank) - Kh_59MK2 = (9, Su57Weapons.Kh_59MK2) - - class Pylon10: - R_73__AA_11_Archer____Infra_Red = (10, Weapons.R_73__AA_11_Archer____Infra_Red) - Smoke_Generator___red = (10, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (10, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (10, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (10, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (10, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (10, Weapons.Smoke_Generator___orange) - - class Pylon11: - R_27R__AA_10_Alamo_A____Semi_Act_Rdr = ( - 11, - Weapons.R_27R__AA_10_Alamo_A____Semi_Act_Rdr, - ) - R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range = ( - 11, - Weapons.R_27ER__AA_10_Alamo_C____Semi_Act_Extended_Range, - ) - R_27T__AA_10_Alamo_B____Infra_Red = ( - 11, - Weapons.R_27T__AA_10_Alamo_B____Infra_Red, - ) - R_27ET__AA_10_Alamo_D____IR_Extended_Range = ( - 11, - Weapons.R_27ET__AA_10_Alamo_D____IR_Extended_Range, - ) - R_77__AA_12_Adder____Active_Rdr = (11, Weapons.R_77__AA_12_Adder____Active_Rdr) - R_73__AA_11_Archer____Infra_Red = (11, Weapons.R_73__AA_11_Archer____Infra_Red) - Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr = ( - 11, - Weapons.Kh_31P__AS_17_Krypton____600kg__ARM__IN__Pas_Rdr, - ) - Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr = ( - 11, - Weapons.Kh_31A__AS_17_Krypton____610kg__AShM__IN__Act_Rdr, - ) - Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser = ( - 11, - Weapons.Kh_29L__AS_14_Kedge____657kg__ASM__Semi_Act_Laser, - ) - Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided = ( - 11, - Weapons.Kh_29T__AS_14_Kedge____670kg__ASM__TV_Guided, - ) - Kh_59M__AS_18_Kazoo____930kg__ASM__IN = ( - 11, - Weapons.Kh_59M__AS_18_Kazoo____930kg__ASM__IN, - ) - MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD = ( - 11, - Weapons.MBD3_U6_68_with_6_x_FAB_100___100kg_GP_Bombs_LD, - ) - B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag = ( - 11, - Weapons.B_13L_pod___5_x_S_13_OF__122mm_UnGd_Rkts__Blast_Frag, - ) - S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator = ( - 11, - Weapons.S_25_OFM___340mm_UnGd_Rkt__480kg_Penetrator, - ) - BetAB_500___500kg_Concrete_Piercing_Bomb_LD = ( - 11, - Weapons.BetAB_500___500kg_Concrete_Piercing_Bomb_LD, - ) - KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag = ( - 11, - Weapons.KMGU_2___96_x_AO_2_5RT_Dispenser__CBU__HE_Frag, - ) - KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP = ( - 11, - Weapons.KMGU_2___96_x_PTAB_2_5KO_Dispenser__CBU__HEAT_AP, - ) - FAB_250___250kg_GP_Bomb_LD = (11, Weapons.FAB_250___250kg_GP_Bomb_LD) - RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP = ( - 11, - Weapons.RBK_250___42_x_PTAB_2_5M__250kg_CBU_Medium_HEAT_AP, - ) - FAB_500_M_62___500kg_GP_Bomb_LD = (11, Weapons.FAB_500_M_62___500kg_GP_Bomb_LD) - RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP = ( - 11, - Weapons.RBK_500_255___30_x_PTAB_10_5__500kg_CBU_Heavy_HEAT_AP, - ) - KAB_500LG___500kg_Laser_Guided_Bomb = ( - 11, - Weapons.KAB_500LG___500kg_Laser_Guided_Bomb, - ) - KAB_500Kr___500kg_TV_Guided_Bomb = ( - 11, - Weapons.KAB_500Kr___500kg_TV_Guided_Bomb, - ) - FAB_1500_M_54___1500kg_GP_Bomb_LD = ( - 11, - Weapons.FAB_1500_M_54___1500kg_GP_Bomb_LD, - ) - KAB_1500L___1500kg_Laser_Guided_Bomb = ( - 11, - Weapons.KAB_1500L___1500kg_Laser_Guided_Bomb, - ) - MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD = ( - 11, - Weapons.MBD3_U6_68_with_6_x_FAB_250___250kg_GP_Bombs_LD, - ) - # ERRR {R-33} - RVV_BD = (11, Su57Weapons.RVV_BD) - RVV_AE = (11, Su57Weapons.RVV_AE) - RVV_M = (11, Su57Weapons.RVV_M) - RVV_L = (11, Su57Weapons.RVV_L) - Fuel_tank_800L_Wing = (11, Weapons.Fuel_tank_800L_Wing) - Su_57_Fuel_Tank = (11, Su57Weapons.Su_57_Fuel_Tank) - RN_28___260_kg__nuclear_bomb__free_fall = ( - 11, - Weapons.RN_28___260_kg__nuclear_bomb__free_fall, - ) - Smoke_Generator___red = (11, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (11, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (11, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (11, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (11, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (11, Weapons.Smoke_Generator___orange) - Kh_59MK2 = (11, Su57Weapons.Kh_59MK2) - - class Pylon12: - R_73__AA_11_Archer____Infra_Red = (12, Weapons.R_73__AA_11_Archer____Infra_Red) - RVV_AE = (12, Su57Weapons.RVV_AE) - RVV_M = (12, Su57Weapons.RVV_M) - Smoke_Generator___red = (12, Weapons.Smoke_Generator___red) - Smoke_Generator___green = (12, Weapons.Smoke_Generator___green) - Smoke_Generator___blue = (12, Weapons.Smoke_Generator___blue) - Smoke_Generator___white = (12, Weapons.Smoke_Generator___white) - Smoke_Generator___yellow = (12, Weapons.Smoke_Generator___yellow) - Smoke_Generator___orange = (12, Weapons.Smoke_Generator___orange) - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} - - tasks = [ - task.CAP, - task.Intercept, - task.Escort, - task.FighterSweep, - task.AFAC, - task.GroundAttack, - task.RunwayAttack, - task.AntishipStrike, - task.CAS, - ] - task_default = task.CAP diff --git a/pydcs_extensions/uh60l/__init__.py b/pydcs_extensions/uh60l/__init__.py deleted file mode 100644 index 5ef2d09ec..000000000 --- a/pydcs_extensions/uh60l/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .uh60l import * diff --git a/pydcs_extensions/uh60l/uh60l.py b/pydcs_extensions/uh60l/uh60l.py deleted file mode 100644 index 5fcc5b883..000000000 --- a/pydcs_extensions/uh60l/uh60l.py +++ /dev/null @@ -1,175 +0,0 @@ -from typing import Any, Dict, Set - -from dcs import task -from dcs.helicopters import HelicopterType -from dcs.planes import PlaneType - -from game.modsupport import helicoptermod, planemod -from pydcs_extensions.weapon_injector import inject_weapons - - -class WeaponsUH60L: - CEFS_Fuel_Tank_200_gallons = { - "clsid": "{UH60_FUEL_TANK_230}", - "name": "CEFS Fuel Tank 200 gallons", - "weight": 730.09478, - } - Cargo_Seats__Rear_Row_ = { - "clsid": "{UH60_SEAT_CARGO_REAR}", - "name": "Cargo Seats (Rear Row)", - "weight": 300, - } - Cargo_Seats__Three_Rows_ = { - "clsid": "{UH60_SEAT_CARGO_ALL}", - "name": "Cargo Seats (Three Rows)", - "weight": 900, - } - Left_Gunner_Seat = { - "clsid": "{UH60_SEAT_GUNNER_L}", - "name": "Left Gunner Seat", - "weight": 100, - } - Right_Gunner_Seat = { - "clsid": "{UH60_SEAT_GUNNER_R}", - "name": "Right Gunner Seat", - "weight": 100, - } - - -inject_weapons(WeaponsUH60L) - - -@helicoptermod -class UH_60L(HelicopterType): - id = "UH-60L" - flyable = True - height = 5.13 - width = 16.4 - length = 19.76 - fuel_max = 1362 - max_speed = 355.584 - chaff = 30 - flare = 60 - charge_total = 90 - chaff_charge_size = 1 - flare_charge_size = 1 - radio_frequency = 124 - - panel_radio = { - 2: { - "channels": { - 1: 264, - 2: 265, - 4: 254, - 8: 258, - 16: 267, - 17: 251, - 9: 262, - 18: 253, - 5: 250, - 10: 259, - 20: 252, - 11: 268, - 3: 256, - 6: 270, - 12: 269, - 13: 260, - 7: 257, - 14: 263, - 19: 266, - 15: 261, - }, - }, - 3: { - "channels": {1: 124, 2: 127.5}, - }, - 1: { - "channels": {6: 41, 2: 31, 8: 50, 3: 32, 1: 30, 4: 33, 5: 40, 7: 42}, - }, - 4: { - "channels": {6: 41, 2: 31, 8: 50, 3: 32, 1: 30, 4: 33, 5: 40, 7: 42}, - }, - 5: { - "channels": {1: 3, 2: 10}, - }, - } - - property_defaults: Dict[str, Any] = { - "FuelProbeEnabled": False, - "NetCrewControlPriority": 1, - } - - class Properties: - class FuelProbeEnabled: - id = "FuelProbeEnabled" - - class NetCrewControlPriority: - id = "NetCrewControlPriority" - - class Values: - Pilot = 0 - Instructor = 1 - Ask_Always = -1 - Equally_Responsible = -2 - - livery_name = "UH-60L" # from type - - class Pylon1: - CEFS_Fuel_Tank_200_gallons = (1, WeaponsUH60L.CEFS_Fuel_Tank_200_gallons) - - # ERRR - - class Pylon2: - CEFS_Fuel_Tank_200_gallons = (2, WeaponsUH60L.CEFS_Fuel_Tank_200_gallons) - - # ERRR - - class Pylon3: - Left_Gunner_Seat = (3, WeaponsUH60L.Left_Gunner_Seat) - - class Pylon4: - Cargo_Seats__Rear_Row_ = (4, WeaponsUH60L.Cargo_Seats__Rear_Row_) - Cargo_Seats__Three_Rows_ = (4, WeaponsUH60L.Cargo_Seats__Three_Rows_) - - class Pylon5: - Right_Gunner_Seat = (5, WeaponsUH60L.Right_Gunner_Seat) - - class Pylon6: - CEFS_Fuel_Tank_200_gallons = (6, WeaponsUH60L.CEFS_Fuel_Tank_200_gallons) - - # ERRR - - class Pylon7: - CEFS_Fuel_Tank_200_gallons = (7, WeaponsUH60L.CEFS_Fuel_Tank_200_gallons) - - # ERRR - - pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7} - - tasks = [task.Transport, task.Reconnaissance] - task_default = task.Transport - - -@planemod -class KC130J(PlaneType): - id = "KC130J" - group_size_max = 1 - height = 11.66 - width = 40.4 - length = 29.79 - fuel_max = 30000 - max_speed = 222.23988 - chaff = 120 - flare = 60 - charge_total = 240 - chaff_charge_size = 1 - flare_charge_size = 2 - tacan = True - category = "Tankers" # {8A302789-A55D-4897-B647-66493FA6826F} - - livery_name = "KC130J" # from type - - pylons: Set[int] = set() - - tasks = [task.Refueling] - task_default = task.Refueling diff --git a/pydcs_extensions/weapon_injector.py b/pydcs_extensions/weapon_injector.py deleted file mode 100644 index 6341c5941..000000000 --- a/pydcs_extensions/weapon_injector.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import List, Any - -from dcs.weapons_data import Weapons, weapon_ids - - -def inject_weapons(weapon_class: Any) -> None: - """ - Inject custom weapons from mods into pydcs weapons databases via introspection - :param weapon_class: The custom weapons class containing dictionaries with weapon info - :return: None - """ - for key, value in weapon_class.__dict__.items(): - if key.startswith("__"): - continue - if isinstance(value, dict) and value.get("clsid"): - setattr(Weapons, key, value) - weapon_ids[value["clsid"]] = value diff --git a/pyinstaller.spec b/pyinstaller.spec deleted file mode 100644 index 93e94fed8..000000000 --- a/pyinstaller.spec +++ /dev/null @@ -1,50 +0,0 @@ -# -*- mode: python -*- - -block_cipher = None - - -analysis = Analysis( - ['./qt_ui/main.py'], - pathex=['.'], - binaries=[], - datas=[ - ('resources', 'resources'), - ('resources/caucasus.p', 'dcs/terrain/'), - ('resources/nevada.p', 'dcs/terrain/'), - ('client/build', 'client/build'), - ], - hookspath=[], - runtime_hooks=[], - excludes=[], - win_no_prefer_redirects=False, - win_private_assemblies=False, - cipher=block_cipher, - noarchive=False, -) -pyz = PYZ( - analysis.pure, - analysis.zipped_data, - cipher=block_cipher, -) -exe = EXE( - pyz, - analysis.scripts, - [], - icon="resources/icon.ico", - exclude_binaries=True, - name='liberation_main', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - console=False, -) -coll = COLLECT( - exe, - analysis.binaries, - analysis.zipfiles, - analysis.datas, - strip=False, - upx=True, - name='dcs_liberation', -) diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index ea7db6740..000000000 --- a/pytest.ini +++ /dev/null @@ -1,9 +0,0 @@ -[pytest] -markers = - fuzztest: marks tests as fuzz tests - -# Disable fuzz tests by default. They're randomized so flaky by nature. They -# are typically run manually after making changes to fuzzed code to generate -# new regression tests. -addopts = - -m "not fuzztest" diff --git a/qt_ui/__init__.py b/qt_ui/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/qt_ui/blocksignals.py b/qt_ui/blocksignals.py deleted file mode 100644 index 8019946a2..000000000 --- a/qt_ui/blocksignals.py +++ /dev/null @@ -1,13 +0,0 @@ -from collections.abc import Iterator -from contextlib import contextmanager - -from PySide6.QtWidgets import QWidget - - -@contextmanager -def block_signals(widget: QWidget) -> Iterator[None]: - blocked = widget.blockSignals(True) - try: - yield - finally: - widget.blockSignals(blocked) diff --git a/qt_ui/cheatcontext.py b/qt_ui/cheatcontext.py deleted file mode 100644 index d3fe6659e..000000000 --- a/qt_ui/cheatcontext.py +++ /dev/null @@ -1,28 +0,0 @@ -from __future__ import annotations - -from collections.abc import Iterator -from contextlib import contextmanager -from typing import TYPE_CHECKING - -from game.server import EventStream -from game.turnstate import TurnState -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.gameoverdialog import GameOverDialog - -if TYPE_CHECKING: - from game import Game - from game.sim import GameUpdateEvents - - -@contextmanager -def game_state_modifying_cheat_context(game: Game) -> Iterator[GameUpdateEvents]: - with EventStream.event_context() as events: - yield events - - state = game.check_win_loss() - if state is not TurnState.CONTINUE: - dialog = GameOverDialog(won=state is TurnState.WIN) - dialog.exec() - else: - game.initialize_turn(events) - GameUpdateSignal.get_instance().updateGame(game) diff --git a/qt_ui/delegates.py b/qt_ui/delegates.py deleted file mode 100644 index dbeca273b..000000000 --- a/qt_ui/delegates.py +++ /dev/null @@ -1,122 +0,0 @@ -from contextlib import contextmanager -from typing import ContextManager, Optional - -from PySide6.QtCore import QModelIndex, Qt, QSize -from PySide6.QtGui import QPainter, QFont, QFontMetrics, QIcon -from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem, QStyle - - -@contextmanager -def painter_context(painter: QPainter) -> ContextManager[None]: - try: - painter.save() - yield - finally: - painter.restore() - - -class TwoColumnRowDelegate(QStyledItemDelegate): - HMARGIN = 4 - VMARGIN = 4 - - def __init__(self, rows: int, columns: int, font_size: int = 12) -> None: - if columns not in (1, 2): - raise ValueError(f"Only one or two columns may be used, not {columns}") - super().__init__() - self.font_size = font_size - self.rows = rows - self.columns = columns - - def get_font(self, option: QStyleOptionViewItem) -> QFont: - font = QFont(option.font) - font.setPointSize(self.font_size) - return font - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - raise NotImplementedError - - def paint( - self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex - ) -> None: - # Draw the list item with all the default selection styling, but with an - # invalid index so text formatting is left to us. - super().paint(painter, option, QModelIndex()) - - rect = option.rect.adjusted( - self.HMARGIN, self.VMARGIN, -self.HMARGIN, -self.VMARGIN - ) - - with painter_context(painter): - painter.setFont(self.get_font(option)) - - icon: Optional[QIcon] = index.data(Qt.DecorationRole) - - if icon is not None: - icon.paint( - painter, - rect, - Qt.AlignLeft | Qt.AlignVCenter, - self.icon_mode(option), - self.icon_state(option), - ) - rect = rect.adjusted(self.icon_size(option).width() + self.HMARGIN, 0, 0, 0) - - row_height = rect.height() / self.rows - for row in range(self.rows): - y = row_height * row - location = rect.adjusted(0, y, 0, y) - painter.drawText(location, Qt.AlignLeft, self.text_for(index, row, 0)) - if self.columns == 2: - painter.drawText( - location, Qt.AlignRight, self.text_for(index, row, 1) - ) - - @staticmethod - def icon_mode(option: QStyleOptionViewItem) -> QIcon.Mode: - if not (option.state & QStyle.State_Enabled): - return QIcon.Disabled - elif option.state & QStyle.State_Selected: - return QIcon.Selected - elif option.state & QStyle.State_Active: - return QIcon.Active - return QIcon.Normal - - @staticmethod - def icon_state(option: QStyleOptionViewItem) -> QIcon.State: - return QIcon.On if option.state & QStyle.State_Open else QIcon.Off - - @staticmethod - def icon_size(option: QStyleOptionViewItem) -> QSize: - icon_size: Optional[QSize] = option.decorationSize - if icon_size is None: - return QSize(0, 0) - else: - return icon_size - - def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize: - metrics = QFontMetrics(self.get_font(option)) - widths = [] - heights = [] - - icon_size = self.icon_size(option) - icon_width = 0 - icon_height = 0 - if icon_size.width(): - icon_width = icon_size.width() + self.HMARGIN - if icon_size.height(): - icon_height = icon_size.height() + self.VMARGIN - - for row in range(self.rows): - width = 0 - height = 0 - for column in range(self.columns): - size = metrics.size(0, self.text_for(index, row, column)) - width += size.width() - height = max(height, size.height()) - widths.append(width) - heights.append(height) - - return QSize( - icon_width + max(widths) + 2 * self.HMARGIN, - max(icon_height, sum(heights)) + 2 * self.VMARGIN, - ) diff --git a/qt_ui/dialogs.py b/qt_ui/dialogs.py deleted file mode 100644 index 920647683..000000000 --- a/qt_ui/dialogs.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Application-wide dialog management.""" -from typing import Optional - -from game.ato.flight import Flight -from game.theater.missiontarget import MissionTarget -from .models import GameModel, PackageModel -from .windows.mission.QEditFlightDialog import QEditFlightDialog -from .windows.mission.QPackageDialog import ( - QEditPackageDialog, - QNewPackageDialog, -) - - -class Dialog: - """Dialog management singleton. - - Opens dialogs and keeps references to dialog windows so that their creators - do not need to worry about the lifetime of the dialog object, and can open - dialogs without needing to have their own reference to common data like the - game model. - """ - - #: The game model. Is only None before initialization, as the game model - #: itself is responsible for handling the case where no game is loaded. - game_model: Optional[GameModel] = None - - new_package_dialog: Optional[QNewPackageDialog] = None - edit_package_dialog: Optional[QEditPackageDialog] = None - edit_flight_dialog: Optional[QEditFlightDialog] = None - - @classmethod - def set_game(cls, game_model: GameModel) -> None: - """Sets the game model.""" - cls.game_model = game_model - - @classmethod - def open_new_package_dialog(cls, mission_target: MissionTarget, parent=None): - """Opens the dialog to create a new package with the given target.""" - cls.new_package_dialog = QNewPackageDialog( - cls.game_model, cls.game_model.ato_model, mission_target, parent=parent - ) - cls.new_package_dialog.show() - - @classmethod - def open_edit_package_dialog(cls, package_model: PackageModel): - """Opens the dialog to edit the given package.""" - cls.edit_package_dialog = QEditPackageDialog( - cls.game_model, cls.game_model.ato_model, package_model - ) - cls.edit_package_dialog.show() - - @classmethod - def open_edit_flight_dialog( - cls, package_model: PackageModel, flight: Flight, parent=None - ) -> None: - """Opens the dialog to edit the given flight.""" - cls.edit_flight_dialog = QEditFlightDialog( - cls.game_model, package_model, flight, parent=parent - ) - cls.edit_flight_dialog.show() diff --git a/qt_ui/errorreporter.py b/qt_ui/errorreporter.py deleted file mode 100644 index f945179f0..000000000 --- a/qt_ui/errorreporter.py +++ /dev/null @@ -1,17 +0,0 @@ -import logging -from collections.abc import Iterator -from contextlib import contextmanager -from typing import Type - -from PySide6.QtWidgets import QDialog, QMessageBox - - -@contextmanager -def report_errors( - title: str, parent: QDialog, error_type: Type[Exception] = Exception -) -> Iterator[None]: - try: - yield - except error_type as ex: - logging.exception(title) - QMessageBox().critical(parent, title, str(ex), QMessageBox.Ok) diff --git a/qt_ui/liberation_install.py b/qt_ui/liberation_install.py deleted file mode 100644 index 5ffd6610b..000000000 --- a/qt_ui/liberation_install.py +++ /dev/null @@ -1,160 +0,0 @@ -import json -import logging -import os -from pathlib import Path -from shutil import copyfile - -import dcs - -from game import persistence - -global __dcs_saved_game_directory -global __dcs_installation_directory -global __last_save_file - - -USER_PATH = Path(os.environ["LOCALAPPDATA"]) / "DCSLiberation" - -PREFERENCES_PATH = USER_PATH / "liberation_preferences.json" - - -def init(): - global __dcs_saved_game_directory - global __dcs_installation_directory - global __last_save_file - global __ignore_empty_install_directory - - if PREFERENCES_PATH.exists(): - try: - logging.debug("Loading Liberation preferences from %s", PREFERENCES_PATH) - with PREFERENCES_PATH.open() as prefs: - pref_data = json.load(prefs) - __dcs_saved_game_directory = pref_data["saved_game_dir"] - __dcs_installation_directory = pref_data["dcs_install_dir"] - __last_save_file = pref_data.get("last_save_file", "") - __ignore_empty_install_directory = pref_data.get( - "ignore_empty_install_directory", False - ) - is_first_start = False - except (KeyError, ValueError): - # KeyError in case of missing contents, ValueError in case of decoding - # errors from a corrupted file. - __dcs_saved_game_directory = "" - __dcs_installation_directory = "" - __last_save_file = "" - __ignore_empty_install_directory = False - is_first_start = True - else: - __last_save_file = "" - __ignore_empty_install_directory = False - try: - __dcs_saved_game_directory = ( - dcs.installation.get_dcs_saved_games_directory() - ) - if os.path.exists(__dcs_saved_game_directory + ".openbeta"): - __dcs_saved_game_directory = ( - dcs.installation.get_dcs_saved_games_directory() + ".openbeta" - ) - except: - __dcs_saved_game_directory = "" - try: - __dcs_installation_directory = dcs.installation.get_dcs_install_directory() - except: - __dcs_installation_directory = "" - - is_first_start = True - persistence.set_dcs_save_game_directory(Path(__dcs_saved_game_directory)) - return is_first_start - - -def setup(saved_game_dir, install_dir): - global __dcs_saved_game_directory - global __dcs_installation_directory - __dcs_saved_game_directory = saved_game_dir - __dcs_installation_directory = install_dir - persistence.set_dcs_save_game_directory(Path(__dcs_saved_game_directory)) - - -def setup_last_save_file(last_save_file: str) -> None: - global __last_save_file - __last_save_file = last_save_file - - -def save_config(): - global __dcs_saved_game_directory - global __dcs_installation_directory - global __last_save_file - global __ignore_empty_install_directory - pref_data = { - "saved_game_dir": __dcs_saved_game_directory, - "dcs_install_dir": __dcs_installation_directory, - "last_save_file": __last_save_file, - "ignore_empty_install_directory": __ignore_empty_install_directory, - } - PREFERENCES_PATH.parent.mkdir(exist_ok=True, parents=True) - with PREFERENCES_PATH.open("w") as prefs: - json.dump(pref_data, prefs, indent=" ") - - -def get_dcs_install_directory(): - global __dcs_installation_directory - return __dcs_installation_directory - - -def get_saved_game_dir(): - global __dcs_saved_game_directory - return __dcs_saved_game_directory - - -def ignore_empty_install_directory(): - global __ignore_empty_install_directory - return __ignore_empty_install_directory - - -def set_ignore_empty_install_directory(value: bool): - global __ignore_empty_install_directory - __ignore_empty_install_directory = value - - -def get_last_save_file() -> Path | None: - global __last_save_file - if os.path.exists(__last_save_file): - return Path(__last_save_file) - else: - return None - - -def replace_mission_scripting_file(): - install_dir = get_dcs_install_directory() - mission_scripting_path = os.path.join( - install_dir, "Scripts", "MissionScripting.lua" - ) - liberation_scripting_path = "./resources/scripts/MissionScripting.lua" - backup_scripting_path = "./resources/scripts/MissionScripting.original.lua" - if install_dir != "" and os.path.isfile(mission_scripting_path): - with open(mission_scripting_path, "r") as ms: - current_file_content = ms.read() - with open(liberation_scripting_path, "r") as libe_ms: - liberation_file_content = libe_ms.read() - - # Save original file - if current_file_content != liberation_file_content: - copyfile(mission_scripting_path, backup_scripting_path) - - # Replace DCS file - copyfile(liberation_scripting_path, mission_scripting_path) - - -def restore_original_mission_scripting(): - install_dir = get_dcs_install_directory() - mission_scripting_path = os.path.join( - install_dir, "Scripts", "MissionScripting.lua" - ) - backup_scripting_path = "./resources/scripts/MissionScripting.original.lua" - - if ( - install_dir != "" - and os.path.isfile(backup_scripting_path) - and os.path.isfile(mission_scripting_path) - ): - copyfile(backup_scripting_path, mission_scripting_path) diff --git a/qt_ui/liberation_theme.py b/qt_ui/liberation_theme.py deleted file mode 100644 index 25eb26a48..000000000 --- a/qt_ui/liberation_theme.py +++ /dev/null @@ -1,87 +0,0 @@ -import json -import logging -import os -from typing import Dict - -global __theme_index - -THEME_PREFERENCES_FILE_PATH = "liberation_theme.json" - -DEFAULT_THEME_INDEX = 1 - - -# new themes can be added here -THEMES: Dict[int, Dict[str, str]] = { - 0: { - "themeName": "Vanilla", - "themeFile": "windows-style.css", - "themeIcons": "medium", - }, - 1: { - "themeName": "DCS World", - "themeFile": "style-dcs.css", - "themeIcons": "light", - }, -} - - -def init(): - global __theme_index - - __theme_index = DEFAULT_THEME_INDEX - - if os.path.isfile(THEME_PREFERENCES_FILE_PATH): - try: - with open(THEME_PREFERENCES_FILE_PATH) as prefs: - pref_data = json.loads(prefs.read()) - __theme_index = pref_data["theme_index"] - set_theme_index(__theme_index) - save_theme_config() - except: - # is this necessary? - set_theme_index(DEFAULT_THEME_INDEX) - logging.exception("Unable to change theme") - else: - # is this necessary? - set_theme_index(DEFAULT_THEME_INDEX) - logging.error( - f"Using default theme because {THEME_PREFERENCES_FILE_PATH} " - "does not exist" - ) - - -# set theme index then use save_theme_config to save to file -def set_theme_index(x): - global __theme_index - __theme_index = x - - -# get theme index to reference other theme properties(themeName, themeFile, themeIcons) -def get_theme_index(): - global __theme_index - return __theme_index - - -# get theme name based on current index -def get_theme_name(): - theme_name = THEMES[get_theme_index()]["themeName"] - return theme_name - - -# get theme icon sub-folder name based on current index -def get_theme_icons(): - theme_icons = THEMES[get_theme_index()]["themeIcons"] - return str(theme_icons) - - -# get theme stylesheet css based on current index -def get_theme_css_file(): - theme_file = THEMES[get_theme_index()]["themeFile"] - return str(theme_file) - - -# save current theme index to json file -def save_theme_config(): - pref_data = {"theme_index": get_theme_index()} - with open(THEME_PREFERENCES_FILE_PATH, "w") as prefs: - prefs.write(json.dumps(pref_data)) diff --git a/qt_ui/logging_handler.py b/qt_ui/logging_handler.py deleted file mode 100644 index a1f16560b..000000000 --- a/qt_ui/logging_handler.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import annotations - -import logging -import typing -from collections.abc import Iterator - -LogHook = typing.Callable[[str], None] - - -class HookableInMemoryHandler(logging.Handler): - """Hookable in-memory logging handler for logs window""" - - _log: str - _hook: typing.Optional[typing.Callable[[str], None]] - - def __init__(self, *args, **kwargs): - super(HookableInMemoryHandler, self).__init__(*args, **kwargs) - self._log = "" - self._hook = None - - @staticmethod - def iter_registered_handlers( - logger: logging.Logger | None = None, - ) -> Iterator[HookableInMemoryHandler]: - if logger is None: - logger = logging.getLogger() - for handler in logger.handlers: - if isinstance(handler, HookableInMemoryHandler): - yield handler - - @property - def log(self) -> str: - return self._log - - def emit(self, record): - msg = self.format(record) - self._log += msg + "\n" - if self._hook is not None: - self._hook(msg) - - def write(self, m): - pass - - def clearLog(self) -> None: - self._log = "" - - def setHook(self, hook: typing.Callable[[str], None]) -> None: - self._hook = hook - - def clearHook(self) -> None: - self._hook = None diff --git a/qt_ui/main.py b/qt_ui/main.py deleted file mode 100644 index d662ba4ee..000000000 --- a/qt_ui/main.py +++ /dev/null @@ -1,448 +0,0 @@ -from __future__ import annotations - -import argparse -import logging -import ntpath -import os -import sys -from dataclasses import dataclass -from datetime import datetime -from pathlib import Path - -import yaml -from PySide6 import QtWidgets -from PySide6.QtCore import Qt -from PySide6.QtGui import QPixmap -from PySide6.QtWidgets import QApplication, QCheckBox, QSplashScreen, QDialog -from dcs.payloads import PayloadDirectories - -from game import Game, VERSION, logging_config, persistence -from game.ato import FlightType -from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET -from game.data.weapons import Pylon, Weapon, WeaponGroup -from game.dcs.aircrafttype import AircraftType -from game.factions.factions import Factions -from game.persistence.paths import liberation_user_dir -from game.plugins import LuaPluginManager -from game.profiling import logged_duration -from game.server import EventStream, Server -from game.settings import Settings -from game.sim import GameUpdateEvents -from game.theater.start_generator import GameGenerator, GeneratorSettings, ModSettings -from pydcs_extensions import load_mods -from qt_ui import ( - liberation_install, - liberation_theme, - uiconstants, -) -from qt_ui.uiflags import UiFlags -from qt_ui.windows.AirWingConfigurationDialog import AirWingConfigurationDialog -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.QLiberationWindow import QLiberationWindow -from qt_ui.windows.preferences.QLiberationFirstStartWindow import ( - QLiberationFirstStartWindow, -) - -THIS_DIR = Path(__file__).parent - - -def inject_custom_payloads(user_path: Path) -> None: - dev_payloads = THIS_DIR.parent / "resources/customized_payloads" - # The packaged release rearranges the file locations, so the release has the - # customized payloads in a different location. - release_payloads = THIS_DIR / "resources/customized_payloads" - if dev_payloads.exists(): - payloads = dev_payloads - elif release_payloads.exists(): - payloads = release_payloads - else: - raise RuntimeError( - f"Could not find customized payloads at {release_payloads} or " - f"{dev_payloads}. Aircraft will have no payloads." - ) - # We configure these as fallbacks so that the user's payloads override ours. - PayloadDirectories.set_fallback(payloads) - PayloadDirectories.set_preferred(user_path / "MissionEditor" / "UnitPayloads") - - -def on_game_load(game: Game | None) -> None: - EventStream.drain() - EventStream.put_nowait(GameUpdateEvents().game_loaded(game)) - - -def run_ui(create_game_params: CreateGameParams | None, ui_flags: UiFlags) -> None: - os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" # Potential fix for 4K screens - QApplication.setHighDpiScaleFactorRoundingPolicy( - Qt.HighDpiScaleFactorRoundingPolicy.PassThrough - ) - - app = QApplication(sys.argv) - - # init the theme and load the stylesheet based on the theme index - liberation_theme.init() - with open( - "./resources/stylesheets/" + liberation_theme.get_theme_css_file(), - encoding="utf-8", - ) as stylesheet: - logging.info("Loading stylesheet: %s", liberation_theme.get_theme_css_file()) - app.setStyleSheet(stylesheet.read()) - - first_start = liberation_install.init() - if first_start: - window = QLiberationFirstStartWindow() - window.exec_() - - logging.info("Using {} as 'Saved Game Folder'".format(persistence.base_path())) - logging.info( - "Using {} as 'DCS installation folder'".format( - liberation_install.get_dcs_install_directory() - ) - ) - - inject_custom_payloads(Path(persistence.base_path())) - - # Splash screen setup - pixmap = QPixmap("./resources/ui/splash_screen.png") - splash = QSplashScreen(pixmap) - splash.show() - - # Once splash screen is up : load resources & setup stuff - uiconstants.load_icons() - uiconstants.load_event_icons() - uiconstants.load_aircraft_icons() - uiconstants.load_vehicle_icons() - - # Show warning if no DCS Installation directory was set - if liberation_install.get_dcs_install_directory() == "": - logging.warning( - "DCS Installation directory is empty. MissionScripting file will not be replaced!" - ) - if not liberation_install.ignore_empty_install_directory(): - ignore_checkbox = QCheckBox("Do not show again") - ignore_checkbox.stateChanged.connect(set_ignore_empty_install_directory) - message_box = QtWidgets.QMessageBox(parent=splash) - message_box.setIcon(QtWidgets.QMessageBox.Icon.Warning) - message_box.setWindowTitle("No DCS installation directory.") - message_box.setText( - "The DCS Installation directory is not set correctly. " - "This will prevent DCS Liberation from working properly, as the MissionScripting " - "file will not be modified." - "

To solve this problem, you can set the Installation directory " - "within the preferences menu. You can also manually edit or replace the " - "following file:" - "

<dcs_installation_directory>/Scripts/MissionScripting.lua" - "

The easiest way to do it is to replace the original file with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)." - "

You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

" - ) - message_box.setDefaultButton(QtWidgets.QMessageBox.StandardButton.Ok) - message_box.setCheckBox(ignore_checkbox) - message_box.exec_() - # Replace DCS Mission scripting file to allow DCS Liberation to work - try: - liberation_install.replace_mission_scripting_file() - except: - error_dialog = QtWidgets.QErrorMessage() - error_dialog.setWindowTitle("Wrong DCS installation directory.") - error_dialog.showMessage( - "Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually." - ) - error_dialog.exec_() - - # Apply CSS (need works) - GameUpdateSignal() - GameUpdateSignal.get_instance().game_loaded.connect(on_game_load) - - game: Game | None = None - if create_game_params is not None: - with logged_duration("New game creation"): - game = create_game(create_game_params) - - # Start window - window = QLiberationWindow(game, ui_flags) - window.showMaximized() - splash.finish(window) - qt_execution_code = app.exec_() - - # Restore Mission Scripting file - logging.info("QT App terminated with status code : " + str(qt_execution_code)) - logging.info("Attempt to restore original mission scripting file") - liberation_install.restore_original_mission_scripting() - logging.info("QT process exited with code : " + str(qt_execution_code)) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser() - subparsers = parser.add_subparsers(dest="subcommand") - - def path_arg(arg: str) -> Path: - path = Path(arg) - if not path.exists(): - raise argparse.ArgumentTypeError("path does not exist") - return path - - parser.add_argument( - "--warn-missing-weapon-data", - action="store_true", - help="Emits a warning for weapons without date or fallback information.", - ) - - parser.add_argument("--dev", action="store_true", help="Enable development mode.") - - speed_controls_group = parser.add_argument_group() - speed_controls_group.add_argument( - "--show-sim-speed-controls", - action="store_true", - default=False, - help="Shows the sim speed controls in the top panel.", - ) - speed_controls_group.add_argument( - "--no-show-sim-speed-controls", - dest="show_sim_speed_controls", - action="store_false", - help="Hides the sim speed controls in the top panel (default).", - ) - - parser.add_argument("--new-map", help="Deprecated. Does nothing.") - parser.add_argument("--old-map", help="Deprecated. Does nothing.") - - new_game = subparsers.add_parser("new-game") - - new_game.add_argument( - "campaign", type=path_arg, help="Path to the campaign to start." - ) - - new_game.add_argument( - "--blue", default="USA 2005", help="Name of the blue faction." - ) - - new_game.add_argument( - "--red", default="Russia 1990", help="Name of the red faction." - ) - - new_game.add_argument( - "--supercarrier", action="store_true", help="Use the supercarrier module." - ) - - new_game.add_argument( - "--auto-procurement", action="store_true", help="Automate bluefor procurement." - ) - - new_game.add_argument( - "--use-new-squadron-rules", - action="store_true", - help="Deprecated. Does nothing.", - ) - - new_game.add_argument( - "--inverted", action="store_true", help="Invert the campaign." - ) - - new_game.add_argument( - "--date", - type=datetime.fromisoformat, - default=datetime.today(), - help="Start date of the campaign.", - ) - - new_game.add_argument( - "--restrict-weapons-by-date", - action="store_true", - help="Enable campaign date restricted weapons.", - ) - - new_game.add_argument("--cheats", action="store_true", help="Enable cheats.") - - new_game.add_argument( - "--advanced-iads", action="store_true", help="Enable advanced IADS." - ) - - new_game.add_argument( - "--show-air-wing-config", - action="store_true", - help="Show the air wing configuration dialog after generating the game.", - ) - - lint_weapons = subparsers.add_parser("lint-weapons") - lint_weapons.add_argument("aircraft", help="Name of the aircraft variant to lint.") - - subparsers.add_parser("dump-task-priorities") - - return parser.parse_args() - - -@dataclass(frozen=True) -class CreateGameParams: - campaign_path: Path - blue: str - red: str - supercarrier: bool - auto_procurement: bool - inverted: bool - cheats: bool - start_date: datetime - restrict_weapons_by_date: bool - advanced_iads: bool - show_air_wing_config: bool - - @staticmethod - def from_args(args: argparse.Namespace) -> CreateGameParams | None: - if args.subcommand != "new-game": - return None - return CreateGameParams( - args.campaign, - args.blue, - args.red, - args.supercarrier, - args.auto_procurement, - args.inverted, - args.cheats, - args.date, - args.restrict_weapons_by_date, - args.advanced_iads, - args.show_air_wing_config, - ) - - -def create_game(params: CreateGameParams) -> Game: - campaign = Campaign.from_file(params.campaign_path) - theater = campaign.load_theater(params.advanced_iads) - faction_loader = Factions.load() - lua_plugin_manager = LuaPluginManager.load() - lua_plugin_manager.merge_player_settings() - generator = GameGenerator( - faction_loader.get_by_name(params.blue), - faction_loader.get_by_name(params.red), - theater, - campaign.load_air_wing_config(theater), - Settings( - supercarrier=params.supercarrier, - automate_runway_repair=params.auto_procurement, - automate_front_line_reinforcements=params.auto_procurement, - automate_aircraft_reinforcements=params.auto_procurement, - enable_frontline_cheats=params.cheats, - enable_base_capture_cheat=params.cheats, - restrict_weapons_by_date=params.restrict_weapons_by_date, - ), - GeneratorSettings( - start_date=params.start_date, - start_time=campaign.recommended_start_time, - player_budget=DEFAULT_BUDGET, - enemy_budget=DEFAULT_BUDGET, - inverted=params.inverted, - advanced_iads=theater.iads_network.advanced_iads, - no_carrier=False, - no_lha=False, - no_player_navy=False, - no_enemy_navy=False, - ), - ModSettings( - a4_skyhawk=False, - f22_raptor=False, - f104_starfighter=False, - hercules=False, - jas39_gripen=False, - su57_felon=False, - frenchpack=False, - high_digit_sams=False, - ), - lua_plugin_manager, - ) - game = generator.generate() - if params.show_air_wing_config: - if AirWingConfigurationDialog(game, None).exec() == QDialog.DialogCode.Rejected: - sys.exit("Aborted air wing configuration") - game.begin_turn_0() - return game - - -def set_ignore_empty_install_directory(value: bool) -> None: - liberation_install.set_ignore_empty_install_directory(value) - liberation_install.save_config() - - -def lint_all_weapon_data() -> None: - for weapon in WeaponGroup.named("Unknown").weapons: - logging.warning(f"No weapon data for {weapon}: {weapon.clsid}") - - -def lint_weapon_data_for_aircraft(aircraft: AircraftType) -> None: - all_weapons: set[Weapon] = set() - for pylon in Pylon.iter_pylons(aircraft): - all_weapons |= pylon.allowed - - for weapon in all_weapons: - if weapon.weapon_group.name == "Unknown": - logging.warning(f'{weapon.clsid} "{weapon.name}" has no weapon data') - - -def fix_pycharm_debugger_if_needed() -> None: - """Applies workaround for a pycharm debugger bug. - - https://youtrack.jetbrains.com/issue/PY-53232/Debugger-doesnt-work-when-pyproj-is-imported - """ - # sys.gettrace() will return something whenever *some* debugger is being used. The - # pdb module will be loaded if that debugger is the built-in python debugger. - if sys.gettrace() is not None and "pdb" not in sys.modules: - logging.debug( - "Applying workaround for https://youtrack.jetbrains.com/issue/PY-53232/Debugger-doesnt-work-when-pyproj-is-imported" - ) - ntpath.sep = "\\" - - -def dump_task_priorities() -> None: - first_start = liberation_install.init() - if first_start: - sys.exit( - "Cannot dump task priorities without configuring DCS Liberation. Start the" - "UI for the first run configuration." - ) - - data: dict[str, dict[str, int]] = {} - for task in FlightType: - data[task.value] = { - a.display_name: a.task_priority(task) - for a in AircraftType.priority_list_for_task(task) - } - - debug_path = liberation_user_dir() / "Debug" / "priorities.yaml" - debug_path.parent.mkdir(parents=True, exist_ok=True) - with debug_path.open("w", encoding="utf-8") as output: - yaml.dump(data, output, sort_keys=False, allow_unicode=True) - - -def main(): - logging_config.init_logging(VERSION) - - logging.debug("Python version %s", sys.version) - - fix_pycharm_debugger_if_needed() - - if not str(Path(__file__)).isascii(): - logging.warning( - "Installation path contains non-ASCII characters. This is known to cause problems." - ) - - args = parse_args() - - # TODO: Flesh out data and then make unconditional. - if args.warn_missing_weapon_data: - lint_all_weapon_data() - - load_mods() - - if args.subcommand == "lint-weapons": - lint_weapon_data_for_aircraft(AircraftType.named(args.aircraft)) - return - if args.subcommand == "dump-task-priorities": - dump_task_priorities() - return - - with Server().run_in_thread(): - run_ui( - CreateGameParams.from_args(args), - UiFlags(args.dev, args.show_sim_speed_controls), - ) - - -if __name__ == "__main__": - main() diff --git a/qt_ui/models.py b/qt_ui/models.py deleted file mode 100644 index 58266f0da..000000000 --- a/qt_ui/models.py +++ /dev/null @@ -1,567 +0,0 @@ -"""Qt data models for game objects.""" -from __future__ import annotations - -import datetime -from typing import Any, Callable, Iterator, Optional, TypeVar - -from PySide6.QtCore import ( - QAbstractListModel, - QModelIndex, - Qt, - Signal, -) -from PySide6.QtGui import QIcon - -from game.ato.airtaaskingorder import AirTaskingOrder -from game.ato.flight import Flight -from game.ato.flighttype import FlightType -from game.ato.package import Package -from game.game import Game -from game.server import EventStream -from game.sim.gameupdateevents import GameUpdateEvents -from game.squadrons.squadron import Pilot, Squadron -from game.theater.missiontarget import MissionTarget -from game.transfers import PendingTransfers, TransferOrder -from qt_ui.simcontroller import SimController -from qt_ui.uiconstants import AIRCRAFT_ICONS - - -class DeletableChildModelManager: - """Manages lifetimes for child models. - - Qt's data models don't have a good way of modeling related data aside from - lists, tables, or trees of similar objects. We could build one monolithic - GameModel that tracks all of the data in the game and use the parent/child - relationships of that model to index down into the ATO, packages, flights, - etc, but doing so is error prone because it requires us to manually manage - that relationship tree and keep our own mappings from row/column into - specific members. - - However, creating child models outside of the tree means that removing an - item from the parent will not signal the child's deletion to any views, so - we must track this explicitly. - - Any model which has child data types should use this class to track the - deletion of child models. All child model types must define a signal named - `deleted`. This signal will be emitted when the child model is being - deleted. Any views displaying such data should subscribe to those events and - update their display accordingly. - """ - - #: The type of data owned by models created by this class. - DataType = TypeVar("DataType") - - #: The type of model managed by this class. - ModelType = TypeVar("ModelType") - - ModelDict = dict[DataType, ModelType] - - def __init__( - self, - create_model: Callable[[DataType, GameModel], ModelType], - game_model: GameModel, - ) -> None: - self.create_model = create_model - self.game_model = game_model - self.models: DeletableChildModelManager.ModelDict = {} - - def acquire(self, data: DataType) -> ModelType: - """Returns a model for the given child data. - - If a model has already been created for the given data, it will be - returned. The data type must be hashable. - """ - if data in self.models: - return self.models[data] - model = self.create_model(data, self.game_model) - self.models[data] = model - return model - - def release(self, data: DataType) -> None: - """Releases the model matching the given data, if one exists. - - If the given data has had a model created for it, that model will be - deleted and its `deleted` signal will be emitted. - """ - if data in self.models: - model = self.models[data] - del self.models[data] - model.deleted.emit() - - def clear(self) -> None: - """Deletes all managed models.""" - for data in list(self.models.keys()): - self.release(data) - - -class NullListModel(QAbstractListModel): - """Generic empty list model.""" - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return 0 - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - return None - - -class PackageModel(QAbstractListModel): - """The model for an ATO package.""" - - FlightRole = Qt.UserRole - - #: Emitted when this package is being deleted from the ATO. - deleted = Signal() - - tot_changed = Signal() - - def __init__(self, package: Package, game_model: GameModel) -> None: - super().__init__() - self.package = package - self.game_model = game_model - self.game_model.sim_controller.sim_update.connect(self.on_sim_update) - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return len(self.package.flights) - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - if not index.isValid(): - return None - flight = self.flight_at_index(index) - if role == Qt.DisplayRole: - return self.text_for_flight(flight) - if role == Qt.DecorationRole: - return self.icon_for_flight(flight) - elif role == PackageModel.FlightRole: - return flight - return None - - @staticmethod - def text_for_flight(flight: Flight) -> str: - """Returns the text that should be displayed for the flight.""" - origin = flight.departure.name - startup = flight.flight_plan.startup_time() - return f"{flight} from {origin} at {startup}" - - @staticmethod - def icon_for_flight(flight: Flight) -> Optional[QIcon]: - """Returns the icon that should be displayed for the flight.""" - name = flight.unit_type.dcs_id - if name in AIRCRAFT_ICONS: - return QIcon(AIRCRAFT_ICONS[name]) - return None - - def add_flight(self, flight: Flight) -> None: - """Adds the given flight to the package.""" - with self.game_model.sim_controller.paused_sim(): - self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) - self.package.add_flight(flight) - # update_tot is not called here because the new flight does not have a - # flight plan yet. Will be called manually by the caller. - self.endInsertRows() - - def cancel_or_abort_flight_at_index(self, index: QModelIndex) -> None: - """Removes the flight at the given index from the package.""" - self.cancel_or_abort_flight(self.flight_at_index(index)) - - def cancel_or_abort_flight(self, flight: Flight) -> None: - with self.game_model.sim_controller.paused_sim(): - if flight.state.cancelable: - self.delete_flight(flight) - EventStream.put_nowait(GameUpdateEvents().delete_flight(flight)) - else: - flight.abort() - EventStream.put_nowait(GameUpdateEvents().update_flight(flight)) - - def delete_flight(self, flight: Flight) -> None: - """Removes the given flight from the package.""" - with self.game_model.sim_controller.paused_sim(): - index = self.package.flights.index(flight) - self.beginRemoveRows(QModelIndex(), index, index) - self.package.remove_flight(flight) - self.endRemoveRows() - self.update_tot() - - def flight_at_index(self, index: QModelIndex) -> Flight: - """Returns the flight located at the given index.""" - return self.package.flights[index.row()] - - def set_tot(self, tot: datetime.datetime) -> datetime: - with self.game_model.sim_controller.paused_sim(): - self.package.time_over_target = tot - self.update_tot() - return self.package.time_over_target - - def set_asap(self, asap: bool) -> None: - with self.game_model.sim_controller.paused_sim(): - self.package.auto_asap = asap - self.update_tot() - - def update_tot(self) -> None: - with self.game_model.sim_controller.paused_sim(): - if self.package.auto_asap: - self.package.set_tot_asap( - self.game_model.sim_controller.current_time_in_sim - ) - self.package.clamp_tot_for_current_time( - self.game_model.sim_controller.current_time_in_sim - ) - self.tot_changed.emit() - # For some reason this is needed to make the UI update quickly. - self.layoutChanged.emit() - - @property - def mission_target(self) -> MissionTarget: - """Returns the mission target of the package.""" - package = self.package - target = package.target - return target - - @property - def description(self) -> str: - """Returns the description of the package.""" - return self.package.package_description - - @property - def flights(self) -> Iterator[Flight]: - """Iterates over the flights in the package.""" - for flight in self.package.flights: - yield flight - - def on_sim_update(self, _events: GameUpdateEvents) -> None: - self.dataChanged.emit(self.index(0), self.index(self.rowCount())) - - -class AtoModel(QAbstractListModel): - """The model for an AirTaskingOrder.""" - - PackageRole = Qt.UserRole - - client_slots_changed = Signal() - packages_changed = Signal() - - def __init__(self, game_model: GameModel, ato: AirTaskingOrder) -> None: - super().__init__() - self.game_model = game_model - self.ato = ato - self.package_models = DeletableChildModelManager(PackageModel, game_model) - self.game_model.sim_controller.sim_update.connect(self.on_sim_update) - - @property - def game(self) -> Optional[Game]: - return self.game_model.game - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return len(self.ato.packages) - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - if not index.isValid(): - return None - package = self.ato.packages[index.row()] - if role == Qt.DisplayRole: - return f"{package.package_description} {package.target.name}" - elif role == AtoModel.PackageRole: - return package - return None - - def add_package(self, package: Package) -> None: - """Adds a package to the ATO.""" - with self.game_model.sim_controller.paused_sim(): - self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) - self.ato.add_package(package) - # We do not need to send events for new flights in the package here. Events - # were already sent when the flights were added to the in-progress package. - self.endInsertRows() - # noinspection PyUnresolvedReferences - self.client_slots_changed.emit() - self.on_packages_changed() - - def cancel_or_abort_package_at_index(self, index: QModelIndex) -> None: - """Removes the package at the given index from the ATO.""" - self.cancel_or_abort_package(self.package_at_index(index)) - - def cancel_or_abort_package(self, package: Package) -> None: - with self.game_model.sim_controller.paused_sim(): - with EventStream.event_context() as events: - if all(f.state.cancelable for f in package.flights): - events.delete_flights_in_package(package) - self._delete_package(package) - return - - package_model = self.find_matching_package_model(package) - for flight in list(package.flights): - if flight.state.cancelable: - package_model.delete_flight(flight) - events.delete_flight(flight) - else: - flight.abort() - events.update_flight(flight) - - def _delete_package(self, package: Package) -> None: - """Removes the given package from the ATO.""" - self.package_models.release(package) - index = self.ato.packages.index(package) - self.beginRemoveRows(QModelIndex(), index, index) - self.ato.remove_package(package) - self.endRemoveRows() - # noinspection PyUnresolvedReferences - self.client_slots_changed.emit() - self.on_packages_changed() - - def on_packages_changed(self) -> None: - if self.game is not None: - with EventStream.event_context() as events: - self.game.compute_unculled_zones(events) - - def package_at_index(self, index: QModelIndex) -> Package: - """Returns the package at the given index.""" - return self.ato.packages[index.row()] - - def replace_from_game(self, player: bool) -> None: - """Updates the ATO object to match the updated game object. - - If the game is None (as is the case when no game has been loaded), an - empty ATO will be used. - """ - self.beginResetModel() - self.package_models.clear() - if self.game is not None: - if player: - self.ato = self.game.blue.ato - else: - self.ato = self.game.red.ato - else: - self.ato = AirTaskingOrder() - self.endResetModel() - # noinspection PyUnresolvedReferences - self.client_slots_changed.emit() - - def get_package_model(self, index: QModelIndex) -> PackageModel: - """Returns a model for the package at the given index.""" - return self.package_models.acquire(self.package_at_index(index)) - - def find_matching_package_model(self, package: Package) -> Optional[PackageModel]: - for model in self.packages: - if model.package == package: - return model - return None - - @property - def packages(self) -> Iterator[PackageModel]: - """Iterates over all the packages in the ATO.""" - for package in self.ato.packages: - yield self.package_models.acquire(package) - - def on_sim_update(self, _events: GameUpdateEvents) -> None: - self.dataChanged.emit(self.index(0), self.index(self.rowCount())) - - -class TransferModel(QAbstractListModel): - """The model for a ground unit transfer.""" - - TransferRole = Qt.UserRole - - def __init__(self, game_model: GameModel) -> None: - super().__init__() - self.game_model = game_model - - @property - def transfers(self) -> PendingTransfers: - return self.game_model.game.coalition_for(player=True).transfers - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return self.transfers.pending_transfer_count - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - if not index.isValid(): - return None - transfer = self.transfer_at_index(index) - if role == Qt.DisplayRole: - return self.text_for_transfer(transfer) - if role == Qt.DecorationRole: - return self.icon_for_transfer(transfer) - elif role == TransferModel.TransferRole: - return transfer - return None - - @staticmethod - def text_for_transfer(transfer: TransferOrder) -> str: - """Returns the text that should be displayed for the transfer.""" - return str(transfer) - - @staticmethod - def icon_for_transfer(_transfer: TransferOrder) -> Optional[QIcon]: - """Returns the icon that should be displayed for the transfer.""" - return None - - def new_transfer(self, transfer: TransferOrder, now: datetime) -> None: - """Updates the game with the new unit transfer.""" - self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) - # TODO: Needs to regenerate base inventory tab. - self.transfers.new_transfer(transfer, now) - self.endInsertRows() - - def cancel_transfer_at_index(self, index: QModelIndex) -> None: - """Cancels the planned unit transfer at the given index.""" - self.cancel_transfer(self.transfer_at_index(index)) - - def cancel_transfer(self, transfer: TransferOrder) -> None: - """Cancels the planned unit transfer at the given index.""" - index = self.transfers.index_of_transfer(transfer) - self.beginRemoveRows(QModelIndex(), index, index) - # TODO: Needs to regenerate base inventory tab. - self.transfers.cancel_transfer(transfer) - self.endRemoveRows() - - def transfer_at_index(self, index: QModelIndex) -> TransferOrder: - """Returns the transfer located at the given index.""" - return self.transfers.transfer_at_index(index.row()) - - -class AirWingModel(QAbstractListModel): - """The model for an air wing.""" - - SquadronRole = Qt.UserRole - - def __init__(self, game_model: GameModel, player: bool) -> None: - super().__init__() - self.game_model = game_model - self.player = player - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return self.game_model.game.air_wing_for(self.player).size - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - if not index.isValid(): - return None - squadron = self.squadron_at_index(index) - if role == Qt.DisplayRole: - return self.text_for_squadron(squadron) - if role == Qt.DecorationRole: - return self.icon_for_squadron(squadron) - elif role == AirWingModel.SquadronRole: - return squadron - return None - - @staticmethod - def text_for_squadron(squadron: Squadron) -> str: - """Returns the text that should be displayed for the squadron.""" - return str(squadron) - - @staticmethod - def icon_for_squadron(squadron: Squadron) -> Optional[QIcon]: - """Returns the icon that should be displayed for the squadron.""" - name = squadron.aircraft.dcs_id - if name in AIRCRAFT_ICONS: - return QIcon(AIRCRAFT_ICONS[name]) - return None - - def squadron_at_index(self, index: QModelIndex) -> Squadron: - """Returns the squadron located at the given index.""" - return self.game_model.game.air_wing_for(self.player).squadron_at_index( - index.row() - ) - - -class SquadronModel(QAbstractListModel): - """The model for a squadron.""" - - PilotRole = Qt.UserRole - - def __init__(self, squadron: Squadron) -> None: - super().__init__() - self.squadron = squadron - - def rowCount(self, parent: QModelIndex = QModelIndex()) -> int: - return self.squadron.number_of_pilots_including_inactive - - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any: - if not index.isValid(): - return None - pilot = self.pilot_at_index(index) - if role == Qt.DisplayRole: - return self.text_for_pilot(pilot) - if role == Qt.DecorationRole: - return self.icon_for_pilot(pilot) - elif role == SquadronModel.PilotRole: - return pilot - return None - - @staticmethod - def text_for_pilot(pilot: Pilot) -> str: - """Returns the text that should be displayed for the pilot.""" - return pilot.name - - @staticmethod - def icon_for_pilot(_pilot: Pilot) -> Optional[QIcon]: - """Returns the icon that should be displayed for the pilot.""" - return None - - def pilot_at_index(self, index: QModelIndex) -> Pilot: - """Returns the pilot located at the given index.""" - return self.squadron.pilot_at_index(index.row()) - - def toggle_ai_state(self, index: QModelIndex) -> None: - pilot = self.pilot_at_index(index) - self.beginResetModel() - pilot.player = not pilot.player - self.endResetModel() - - def toggle_leave_state(self, index: QModelIndex) -> None: - pilot = self.pilot_at_index(index) - self.beginResetModel() - if pilot.on_leave: - self.squadron.return_from_leave(pilot) - else: - self.squadron.send_on_leave(pilot) - self.endResetModel() - - def is_auto_assignable(self, task: FlightType) -> bool: - return task in self.squadron.auto_assignable_mission_types - - def set_auto_assignable(self, task: FlightType, auto_assignable: bool) -> None: - if auto_assignable: - self.squadron.auto_assignable_mission_types.add(task) - else: - self.squadron.auto_assignable_mission_types.remove(task) - - -class GameModel: - """A model for the Game object. - - This isn't a real Qt data model, but simplifies management of the game and - its ATO objects. - """ - - def __init__(self, game: Optional[Game], sim_controller: SimController) -> None: - self.game: Optional[Game] = game - self.sim_controller = sim_controller - self.transfer_model = TransferModel(self) - self.blue_air_wing_model = AirWingModel(self, player=True) - if self.game is None: - self.ato_model = AtoModel(self, AirTaskingOrder()) - self.red_ato_model = AtoModel(self, AirTaskingOrder()) - else: - self.ato_model = AtoModel(self, self.game.blue.ato) - self.red_ato_model = AtoModel(self, self.game.red.ato) - - def ato_model_for(self, player: bool) -> AtoModel: - if player: - return self.ato_model - return self.red_ato_model - - def set(self, game: Optional[Game]) -> None: - """Updates the managed Game object. - - The argument will be None when no game has been loaded. In this state, - much of the UI is still visible and needs to handle that behavior. To - simplify that case, the AtoModel will model an empty ATO when no game is - loaded. - """ - self.game = game - self.ato_model.replace_from_game(player=True) - self.red_ato_model.replace_from_game(player=False) - - def get(self) -> Game: - if self.game is None: - raise RuntimeError("GameModel has no Game set") - return self.game diff --git a/qt_ui/simcontroller.py b/qt_ui/simcontroller.py deleted file mode 100644 index 18675139b..000000000 --- a/qt_ui/simcontroller.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -import logging -from collections.abc import Iterator -from contextlib import contextmanager -from datetime import datetime, timedelta -from pathlib import Path -from typing import Callable, Optional, TYPE_CHECKING - -from PySide6.QtCore import QObject, Signal - -from game.polldebriefingfilethread import PollDebriefingFileThread -from game.sim.gameloop import GameLoop -from game.sim.gameupdatecallbacks import GameUpdateCallbacks -from game.sim.gameupdateevents import GameUpdateEvents -from game.sim.simspeedsetting import SimSpeedSetting - -if TYPE_CHECKING: - from game import Game - from game.debriefing import Debriefing - - -class SimController(QObject): - sim_update = Signal(GameUpdateEvents) - sim_speed_changed = Signal(SimSpeedSetting) - simulation_complete = Signal() - - def __init__(self, game: Optional[Game]) -> None: - super().__init__() - self.game_loop: Optional[GameLoop] = None - self.recreate_game_loop(game) - self.started = False - - @property - def completed(self) -> bool: - return self.game_loop.completed - - @property - def current_time_in_sim_if_game_loaded(self) -> datetime | None: - if self.game_loop is None: - return None - return self.game_loop.current_time_in_sim - - @property - def current_time_in_sim(self) -> datetime: - time = self.current_time_in_sim_if_game_loaded - if time is None: - raise RuntimeError("No game is loaded") - return time - - @property - def elapsed_time(self) -> timedelta: - if self.game_loop is None: - return timedelta() - return self.game_loop.elapsed_time - - def set_game(self, game: Optional[Game]) -> None: - self.sim_speed_changed.emit(SimSpeedSetting.PAUSED) - self.recreate_game_loop(game) - - def recreate_game_loop(self, game: Optional[Game]) -> None: - if self.game_loop is not None: - self.game_loop.pause() - self.game_loop = None - if game is not None: - self.game_loop = GameLoop( - game, - GameUpdateCallbacks(self.on_simulation_complete, self.sim_update.emit), - ) - self.started = False - - def set_simulation_speed(self, simulation_speed: SimSpeedSetting) -> None: - if self.game_loop.completed and simulation_speed is not SimSpeedSetting.PAUSED: - logging.debug("Cannot unpause sim: already complete") - return - if not self.started and simulation_speed is not SimSpeedSetting.PAUSED: - self.game_loop.start() - self.started = True - self.sim_speed_changed.emit(simulation_speed) - self.game_loop.set_simulation_speed(simulation_speed) - - @contextmanager - def paused_sim(self) -> Iterator[None]: - with self.game_loop.paused_sim(): - yield - - def run_to_first_contact(self) -> None: - self.game_loop.run_to_first_contact() - - def generate_miz(self, output: Path) -> None: - self.game_loop.pause_and_generate_miz(output) - - def wait_for_debriefing( - self, callback: Callable[[Debriefing], None] - ) -> PollDebriefingFileThread: - thread = PollDebriefingFileThread(callback, self.game_loop.sim) - thread.start() - return thread - - def debrief_current_state( - self, state_path: Path, force_end: bool = False - ) -> Debriefing: - return self.game_loop.pause_and_debrief(state_path, force_end) - - def process_results(self, debriefing: Debriefing) -> None: - return self.game_loop.complete_with_results(debriefing) - - def on_simulation_complete(self) -> None: - logging.debug("Simulation complete") - self.sim_speed_changed.emit(SimSpeedSetting.PAUSED) - self.simulation_complete.emit() diff --git a/qt_ui/uiconstants.py b/qt_ui/uiconstants.py deleted file mode 100644 index 64826a82f..000000000 --- a/qt_ui/uiconstants.py +++ /dev/null @@ -1,213 +0,0 @@ -import os -from typing import Dict - -from PySide6.QtGui import QPixmap - -from .liberation_theme import get_theme_icons - -LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Neutral Dot", "Off"] -SKILL_OPTIONS = ["Average", "Good", "High", "Excellent"] - -AIRCRAFT_ICONS: Dict[str, QPixmap] = {} -VEHICLES_ICONS: Dict[str, QPixmap] = {} -ICONS: Dict[str, QPixmap] = {} - - -def load_icons(): - ICONS["New"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/new.png") - ICONS["Open"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/open.png") - ICONS["Save"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/save.png") - ICONS["Discord"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/discord.png" - ) - ICONS["Github"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/github.png" - ) - ICONS["Bug"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/bug.png") - ICONS["Ukraine"] = QPixmap("./resources/ui/misc/ukraine.png") - - ICONS["Control Points"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/circle.png" - ) - ICONS["Ground Objects"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/industry.png" - ) - ICONS["Lines"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/arrows-h.png" - ) - ICONS["Waypoint Information"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/info.png" - ) - ICONS["Map Polygon Debug Mode"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/map.png" - ) - ICONS["Ally SAM Threat Range"] = QPixmap("./resources/ui/misc/blue-sam.png") - ICONS["Enemy SAM Threat Range"] = QPixmap("./resources/ui/misc/red-sam.png") - ICONS["SAM Detection Range"] = QPixmap("./resources/ui/misc/detection-sam.png") - ICONS["Display Culling Zones"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/eraser.png" - ) - ICONS["Hide Flight Paths"] = QPixmap("./resources/ui/misc/hide-flight-path.png") - ICONS["Show Selected Flight Path"] = QPixmap("./resources/ui/misc/flight-path.png") - ICONS["Show All Flight Paths"] = QPixmap("./resources/ui/misc/all-flight-paths.png") - - ICONS["Hangar"] = QPixmap("./resources/ui/misc/hangar.png") - - ICONS["Dawn"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/timeofday/dawn.png" - ) - ICONS["Day"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/timeofday/day.png" - ) - ICONS["Dusk"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/timeofday/dusk.png" - ) - ICONS["Night"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/timeofday/night.png" - ) - - ICONS["Money"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/money_icon.png" - ) - ICONS["Campaign Management"] = ICONS["Money"] - ICONS["PassTurn"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/hourglass.png" - ) - ICONS["Proceed"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/proceed.png" - ) - ICONS["Settings"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/settings.png" - ) - ICONS["Statistics"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/statistics.png" - ) - ICONS["Ordnance"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/ordnance_icon.png" - ) - - ICONS["Generator"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/generator.png" - ) - ICONS["Mission Generation"] = ICONS["Generator"] - ICONS["Missile"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/missile.png" - ) - ICONS["Difficulty"] = ICONS["Missile"] - ICONS["Cheat"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/cheat.png") - ICONS["Plugins"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/plugins.png" - ) - ICONS["PluginsOptions"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/pluginsoptions.png" - ) - ICONS["Notes"] = QPixmap("./resources/ui/misc/" + get_theme_icons() + "/notes.png") - ICONS["Reload"] = QPixmap( - "./resources/ui/misc/" + get_theme_icons() + "/reload.png" - ) - - ICONS["TaskCAS"] = QPixmap("./resources/ui/tasks/cas.png") - ICONS["TaskCAP"] = QPixmap("./resources/ui/tasks/cap.png") - ICONS["TaskSEAD"] = QPixmap("./resources/ui/tasks/sead.png") - ICONS["TaskEmpty"] = QPixmap("./resources/ui/tasks/empty.png") - - """ - Weather Icons - """ - ICONS["Weather_winds"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/winds.png" - ) - ICONS["Weather_day-clear"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/day-clear.png" - ) - ICONS["Weather_day-cloudy-fog"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/day-cloudy-fog.png" - ) - ICONS["Weather_day-fog"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/day-fog.png" - ) - ICONS["Weather_day-partly-cloudy"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/day-partly-cloudy.png" - ) - ICONS["Weather_day-rain"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/day-rain.png" - ) - ICONS["Weather_day-thunderstorm"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/day-thunderstorm.png" - ) - ICONS["Weather_day-totally-cloud"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/day-totally-cloud.png" - ) - ICONS["Weather_night-clear"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/night-clear.png" - ) - ICONS["Weather_night-cloudy-fog"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/night-cloudy-fog.png" - ) - ICONS["Weather_night-fog"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/night-fog.png" - ) - ICONS["Weather_night-partly-cloudy"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/night-partly-cloudy.png" - ) - ICONS["Weather_night-rain"] = QPixmap( - "./resources/ui/conditions/" + get_theme_icons() + "/weather/night-rain.png" - ) - ICONS["Weather_night-thunderstorm"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/night-thunderstorm.png" - ) - ICONS["Weather_night-totally-cloud"] = QPixmap( - "./resources/ui/conditions/" - + get_theme_icons() - + "/weather/night-totally-cloud.png" - ) - - ICONS["heading"] = QPixmap("./resources/ui/misc/heading.png") - - -EVENT_ICONS: Dict[str, QPixmap] = {} - - -def load_event_icons(): - for image in os.listdir("./resources/ui/events/"): - if image.endswith(".PNG"): - EVENT_ICONS[image[:-4]] = QPixmap( - os.path.join("./resources/ui/events/", image) - ) - - -def load_aircraft_icons(): - for aircraft in os.listdir("./resources/ui/units/aircrafts/icons/"): - if aircraft.endswith(".jpg"): - AIRCRAFT_ICONS[aircraft[:-7]] = QPixmap( - os.path.join("./resources/ui/units/aircrafts/icons/", aircraft) - ) - AIRCRAFT_ICONS["F-16C_50"] = AIRCRAFT_ICONS["F-16C"] - AIRCRAFT_ICONS["FA-18C_hornet"] = AIRCRAFT_ICONS["FA-18C"] - AIRCRAFT_ICONS["A-10C_2"] = AIRCRAFT_ICONS["A-10C"] - f1_refuel = ["Mirage-F1CT", "Mirage-F1EE", "Mirage-F1M-EE", "Mirage-F1EQ"] - for f1 in f1_refuel: - AIRCRAFT_ICONS[f1] = AIRCRAFT_ICONS["Mirage-F1C-200"] - AIRCRAFT_ICONS["Mirage-F1M-CE"] = AIRCRAFT_ICONS["Mirage-F1CE"] - AIRCRAFT_ICONS["MB-339A"] = AIRCRAFT_ICONS["MB-339A PAN"] - AIRCRAFT_ICONS["F-15ESE"] = AIRCRAFT_ICONS["F-15E"] - - -def load_vehicle_icons(): - for vehicle in os.listdir("./resources/ui/units/vehicles/icons/"): - if vehicle.endswith(".jpg"): - VEHICLES_ICONS[vehicle[:-7]] = QPixmap( - os.path.join("./resources/ui/units/vehicles/icons/", vehicle) - ) diff --git a/qt_ui/uiflags.py b/qt_ui/uiflags.py deleted file mode 100644 index e13effba6..000000000 --- a/qt_ui/uiflags.py +++ /dev/null @@ -1,17 +0,0 @@ -from dataclasses import dataclass - - -@dataclass(frozen=True) -class UiFlags: - """Flags for the UI that are not exposed in settings. - - These flags are hidden from the settings UI because they can only be controlled from - the command-line during startup. - """ - - # True if the front-end should connect to the development react webserver instead of - # the built front-end app. - dev_ui_webserver: bool - - # True if the play/pause/speed controls should be visible in the top panel. - show_sim_speed_controls: bool diff --git a/qt_ui/uncaughtexceptionhandler.py b/qt_ui/uncaughtexceptionhandler.py deleted file mode 100644 index 3b32ab9ff..000000000 --- a/qt_ui/uncaughtexceptionhandler.py +++ /dev/null @@ -1,42 +0,0 @@ -# From https://timlehr.com/python-exception-hooks-with-qt-message-box/ -import logging -import sys -import traceback - -from PySide6.QtCore import Signal, QObject -from PySide6.QtWidgets import QMessageBox, QApplication - - -class UncaughtExceptionHandler(QObject): - _exception_caught = Signal(str, str) - - def __init__(self, parent: QObject): - super().__init__(parent) - sys.excepthook = self.exception_hook - # Use a signal so that the message box always comes from the main thread. - self._exception_caught.connect(self.show_exception_box) - - def exception_hook(self, exc_type, exc_value, exc_traceback): - if issubclass(exc_type, KeyboardInterrupt): - # Ignore keyboard interrupt to support console applications. - sys.__excepthook__(exc_type, exc_value, exc_traceback) - return - - logging.exception( - "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback) - ) - self._exception_caught.emit( - str(exc_value), - "".join(traceback.format_exception(exc_type, exc_value, exc_traceback)), - ) - - def show_exception_box(self, message: str, exception: str) -> None: - if QApplication.instance() is not None: - QMessageBox().critical( - QApplication.focusWidget(), - "An unexpected error occurred", - "\n".join([message, "", exception]), - QMessageBox.Ok, - ) - else: - logging.critical("No QApplication instance available.") diff --git a/qt_ui/widgets/QBudgetBox.py b/qt_ui/widgets/QBudgetBox.py deleted file mode 100644 index ecf75f067..000000000 --- a/qt_ui/widgets/QBudgetBox.py +++ /dev/null @@ -1,49 +0,0 @@ -from PySide6.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QPushButton - -import qt_ui.uiconstants as CONST -from game import Game -from game.income import Income -from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu - - -class QBudgetBox(QGroupBox): - """ - UI Component to display current budget and player's money - """ - - def __init__(self, game: Game): - super(QBudgetBox, self).__init__("Budget") - - self.game = game - - self.finances = QPushButton() - self.finances.setDisabled(True) - self.finances.setProperty("style", "btn-primary") - self.finances.setIcon(CONST.ICONS["Money"]) - self.finances.clicked.connect(self.openFinances) - - self.layout = QHBoxLayout() - self.layout.addWidget(self.finances) - self.setLayout(self.layout) - - def setBudget(self, budget, reward): - """ - Set the money amount to display - :param budget: Current money available - :param reward: Planned reward for next turn - """ - self.finances.setText( - str(round(budget, 2)) + "M (+" + str(round(reward, 2)) + "M)" - ) - - def setGame(self, game): - if game is None: - return - - self.game = game - self.setBudget(self.game.blue.budget, Income(self.game, player=True).total) - self.finances.setEnabled(True) - - def openFinances(self): - self.subwindow = QFinancesMenu(self.game) - self.subwindow.show() diff --git a/qt_ui/widgets/QConditionsWidget.py b/qt_ui/widgets/QConditionsWidget.py deleted file mode 100644 index 37c26d65e..000000000 --- a/qt_ui/widgets/QConditionsWidget.py +++ /dev/null @@ -1,316 +0,0 @@ -from datetime import datetime - -from PySide6.QtGui import QPixmap -from PySide6.QtWidgets import ( - QFrame, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QVBoxLayout, -) -from dcs.weather import CloudPreset, Weather as PydcsWeather - -import qt_ui.uiconstants as CONST -from game.sim.gameupdateevents import GameUpdateEvents -from game.timeofday import TimeOfDay -from game.utils import mps -from game.weather.conditions import Conditions -from qt_ui.simcontroller import SimController - - -class QTimeTurnWidget(QGroupBox): - """ - UI Component to display current turn and time info - """ - - def __init__(self, sim_controller: SimController) -> None: - super(QTimeTurnWidget, self).__init__("Turn") - self.sim_controller = sim_controller - self.setStyleSheet( - "padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px" - ) - - self.icons = { - TimeOfDay.Dawn: CONST.ICONS["Dawn"], - TimeOfDay.Day: CONST.ICONS["Day"], - TimeOfDay.Dusk: CONST.ICONS["Dusk"], - TimeOfDay.Night: CONST.ICONS["Night"], - } - - # self.setProperty('style', 'conditions__widget--turn') - self.layout = QHBoxLayout() - self.setLayout(self.layout) - - self.daytime_icon = QLabel() - self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn]) - self.layout.addWidget(self.daytime_icon) - - self.time_column = QVBoxLayout() - self.layout.addLayout(self.time_column) - - self.date_display = QLabel() - self.time_column.addWidget(self.date_display) - - self.time_display = QLabel() - self.time_column.addWidget(self.time_display) - - sim_controller.sim_update.connect(self.on_sim_update) - - def on_sim_update(self, _events: GameUpdateEvents) -> None: - time = self.sim_controller.current_time_in_sim_if_game_loaded - if time is None: - self.date_display.setText("") - self.time_display.setText("") - else: - self.set_date_and_time(time) - - def set_current_turn(self, turn: int, conditions: Conditions) -> None: - """Sets the turn information display. - - :arg turn Current turn number. - :arg conditions Current time and weather conditions. - """ - self.daytime_icon.setPixmap(self.icons[conditions.time_of_day]) - self.set_date_and_time(conditions.start_time) - self.setTitle(f"Turn {turn}") - - def set_date_and_time(self, time: datetime) -> None: - self.date_display.setText(time.strftime("%d %b %Y")) - self.time_display.setText(time.strftime("%H:%M:%S Local")) - - -class QWeatherWidget(QGroupBox): - """ - UI Component to display current weather forecast - """ - - turn = None - conditions = None - - def __init__(self): - super(QWeatherWidget, self).__init__("") - self.setProperty("style", "QWeatherWidget") - - self.icons = { - TimeOfDay.Dawn: CONST.ICONS["Dawn"], - TimeOfDay.Day: CONST.ICONS["Day"], - TimeOfDay.Dusk: CONST.ICONS["Dusk"], - TimeOfDay.Night: CONST.ICONS["Night"], - } - - self.layout = QHBoxLayout() - self.setLayout(self.layout) - - self.makeWeatherIcon() - self.makeCloudRainFogWidget() - self.makeWindsWidget() - - def makeWeatherIcon(self): - """Makes the Weather Icon Widget""" - self.weather_icon = QLabel() - self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn]) - self.layout.addWidget(self.weather_icon) - - def makeCloudRainFogWidget(self): - """Makes the Cloud, Rain, Fog Widget""" - self.textLayout = QVBoxLayout() - self.layout.addLayout(self.textLayout) - - self.forecastClouds = self.makeLabel() - self.textLayout.addWidget(self.forecastClouds) - - self.forecastRain = self.makeLabel() - self.textLayout.addWidget(self.forecastRain) - - self.forecastFog = self.makeLabel() - self.textLayout.addWidget(self.forecastFog) - - def makeWindsWidget(self): - """Factory for the winds widget.""" - windsLayout = QGridLayout() - self.layout.addLayout(windsLayout) - - windsLayout.addWidget(self.makeIcon(CONST.ICONS["Weather_winds"]), 0, 0, 3, 1) - - windsLayout.addWidget(self.makeLabel("At GL"), 0, 1) - windsLayout.addWidget(self.makeLabel("At FL08"), 1, 1) - windsLayout.addWidget(self.makeLabel("At FL26"), 2, 1) - - self.windGLSpeedLabel = self.makeLabel("0kts") - self.windGLDirLabel = self.makeLabel("0º") - windsLayout.addWidget(self.windGLSpeedLabel, 0, 2) - windsLayout.addWidget(self.windGLDirLabel, 0, 3) - - self.windFL08SpeedLabel = self.makeLabel("0kts") - self.windFL08DirLabel = self.makeLabel("0º") - windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2) - windsLayout.addWidget(self.windFL08DirLabel, 1, 3) - - self.windFL26SpeedLabel = self.makeLabel("0kts") - self.windFL26DirLabel = self.makeLabel("0º") - windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2) - windsLayout.addWidget(self.windFL26DirLabel, 2, 3) - - def makeLabel(self, text: str = "") -> QLabel: - """Shorthand to generate a QLabel with widget standard style - - :arg pixmap QPixmap for the icon. - """ - label = QLabel(text) - label.setProperty("style", "text-sm") - - return label - - def makeIcon(self, pixmap: QPixmap) -> QLabel: - """Shorthand to generate a QIcon with pixmap. - - :arg pixmap QPixmap for the icon. - """ - icon = QLabel() - icon.setPixmap(pixmap) - - return icon - - def setCurrentTurn(self, turn: int, conditions: Conditions) -> None: - """Sets the turn information display. - - :arg turn Current turn number. - :arg conditions Current time and weather conditions. - """ - self.turn = turn - self.conditions = conditions - - self.update_forecast() - self.updateWinds() - - def updateWinds(self): - """Updates the UI with the current conditions wind info.""" - windGlSpeed = mps(self.conditions.weather.wind.at_0m.speed or 0) - windGlDir = str(self.conditions.weather.wind.at_0m.direction or 0).rjust(3, "0") - self.windGLSpeedLabel.setText(f"{int(windGlSpeed.knots)}kts") - self.windGLDirLabel.setText(f"{windGlDir}º") - - windFL08Speed = mps(self.conditions.weather.wind.at_2000m.speed or 0) - windFL08Dir = str(self.conditions.weather.wind.at_2000m.direction or 0).rjust( - 3, "0" - ) - self.windFL08SpeedLabel.setText(f"{int(windFL08Speed.knots)}kts") - self.windFL08DirLabel.setText(f"{windFL08Dir}º") - - windFL26Speed = mps(self.conditions.weather.wind.at_8000m.speed or 0) - windFL26Dir = str(self.conditions.weather.wind.at_8000m.direction or 0).rjust( - 3, "0" - ) - self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts") - self.windFL26DirLabel.setText(f"{windFL26Dir}º") - - def update_forecast_from_preset(self, preset: CloudPreset) -> None: - self.forecastFog.setText("No fog") - if "Rain" in preset.name: - self.forecastRain.setText("Rain") - self.update_forecast_icons("rain") - else: - self.forecastRain.setText("No rain") - self.update_forecast_icons("partly-cloudy") - - # We get a description like the following for the cloud preset. - # - # 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41 - # - # The second line is probably interesting but doesn't fit into the widget - # currently, so for now just extract the first line. - self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1]) - - def update_forecast(self): - """Updates the Forecast Text and icon with the current conditions wind info.""" - if ( - self.conditions.weather.clouds - and self.conditions.weather.clouds.preset is not None - ): - self.update_forecast_from_preset(self.conditions.weather.clouds.preset) - return - - if self.conditions.weather.clouds is None: - cloud_density = 0 - precipitation = None - else: - cloud_density = self.conditions.weather.clouds.density - precipitation = self.conditions.weather.clouds.precipitation - - if not cloud_density: - self.forecastClouds.setText("Clear") - weather_type = "clear" - elif cloud_density < 3: - self.forecastClouds.setText("Partly Cloudy") - weather_type = "partly-cloudy" - elif cloud_density < 5: - self.forecastClouds.setText("Mostly Cloudy") - weather_type = "partly-cloudy" - else: - self.forecastClouds.setText("Totally Cloudy") - weather_type = "partly-cloudy" - - if precipitation == PydcsWeather.Preceptions.Rain: - self.forecastRain.setText("Rain") - weather_type = "rain" - elif precipitation == PydcsWeather.Preceptions.Thunderstorm: - self.forecastRain.setText("Thunderstorm") - weather_type = "thunderstorm" - else: - self.forecastRain.setText("No rain") - - if not self.conditions.weather.fog is not None: - self.forecastFog.setText("No fog") - else: - visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1) - self.forecastFog.setText(f"Fog vis: {visibility}nm") - if cloud_density > 1: - weather_type = "cloudy-fog" - else: - weather_type = "fog" - - self.update_forecast_icons(weather_type) - - def update_forecast_icons(self, weather_type: str) -> None: - time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day" - icon_key = f"Weather_{time}-{weather_type}" - icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"] - self.weather_icon.setPixmap(icon) - - -class QConditionsWidget(QFrame): - """ - UI Component to display Turn Number, Day Time & Hour and weather combined. - """ - - def __init__(self, sim_controller: SimController) -> None: - super(QConditionsWidget, self).__init__() - self.setProperty("style", "QConditionsWidget") - - self.layout = QGridLayout() - self.layout.setContentsMargins(0, 0, 0, 0) - self.layout.setHorizontalSpacing(0) - self.layout.setVerticalSpacing(0) - self.setLayout(self.layout) - - self.time_turn_widget = QTimeTurnWidget(sim_controller) - self.time_turn_widget.setStyleSheet("QGroupBox { margin-right: 0px; }") - self.layout.addWidget(self.time_turn_widget, 0, 0) - - self.weather_widget = QWeatherWidget() - self.weather_widget.setStyleSheet( - "QGroupBox { margin-top: 5px; margin-left: 0px; border-left: 0px; }" - ) - self.weather_widget.hide() - self.layout.addWidget(self.weather_widget, 0, 1) - - def setCurrentTurn(self, turn: int, conditions: Conditions) -> None: - """Sets the turn information display. - - :arg turn Current turn number. - :arg conditions Current time and weather conditions. - """ - self.time_turn_widget.set_current_turn(turn, conditions) - self.weather_widget.setCurrentTurn(turn, conditions) - self.weather_widget.show() diff --git a/qt_ui/widgets/QDebriefingInformation.py b/qt_ui/widgets/QDebriefingInformation.py deleted file mode 100644 index c397ac668..000000000 --- a/qt_ui/widgets/QDebriefingInformation.py +++ /dev/null @@ -1,11 +0,0 @@ -from PySide6.QtWidgets import QFrame - - -class QDebriefingInformation(QFrame): - """ - UI component to display debreifing informations - """ - - def __init__(self): - super(QDebriefingInformation, self).__init__() - self.init_ui() diff --git a/qt_ui/widgets/QFactionsInfos.py b/qt_ui/widgets/QFactionsInfos.py deleted file mode 100644 index aabc6fc22..000000000 --- a/qt_ui/widgets/QFactionsInfos.py +++ /dev/null @@ -1,31 +0,0 @@ -from PySide6.QtWidgets import QLabel, QGroupBox, QGridLayout -from game import Game - - -class QFactionsInfos(QGroupBox): - """ - UI Component to display current turn and time info - """ - - def __init__(self, game): - super(QFactionsInfos, self).__init__("Factions") - - self.player_name = QLabel("") - self.enemy_name = QLabel("") - self.setGame(game) - - self.layout = QGridLayout() - self.layout.setSpacing(0) - self.layout.addWidget(QLabel("Player : "), 0, 0) - self.layout.addWidget(self.player_name, 0, 1) - self.layout.addWidget(QLabel("Enemy : "), 1, 0) - self.layout.addWidget(self.enemy_name, 1, 1) - self.setLayout(self.layout) - - def setGame(self, game: Game): - if game is not None: - self.player_name.setText(game.blue.faction.name) - self.enemy_name.setText(game.red.faction.name) - else: - self.player_name.setText("") - self.enemy_name.setText("") diff --git a/qt_ui/widgets/QFlightSizeSpinner.py b/qt_ui/widgets/QFlightSizeSpinner.py deleted file mode 100644 index 0ec0bd632..000000000 --- a/qt_ui/widgets/QFlightSizeSpinner.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Spin box for selecting the number of aircraft in a flight.""" -from PySide6.QtWidgets import QSpinBox - - -class QFlightSizeSpinner(QSpinBox): - """Spin box for selecting the number of aircraft in a flight.""" - - def __init__( - self, min_size: int = 1, max_size: int = 4, default_size: int = 2 - ) -> None: - super().__init__() - self.setMinimum(min_size) - self.setMaximum(max_size) - self.setValue(default_size) diff --git a/qt_ui/widgets/QIntelBox.py b/qt_ui/widgets/QIntelBox.py deleted file mode 100644 index 5e3deaf59..000000000 --- a/qt_ui/widgets/QIntelBox.py +++ /dev/null @@ -1,123 +0,0 @@ -from typing import Optional - -from PySide6.QtWidgets import ( - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QPushButton, -) - -from game import Game -from game.income import Income -from qt_ui.windows.intel import IntelWindow - - -class QIntelBox(QGroupBox): - def __init__(self, game: Game) -> None: - super().__init__("Intel") - self.setProperty("style", "IntelSummary") - - self.game = game - - columns = QHBoxLayout() - self.setLayout(columns) - - summary = QGridLayout() - summary.setContentsMargins(5, 5, 5, 5) - - air_superiority = QLabel("Air superiority:") - summary.addWidget(air_superiority, 0, 0) - self.air_strength = QLabel() - summary.addWidget(self.air_strength, 0, 1) - - front_line = QLabel("Front line:") - summary.addWidget(front_line, 1, 0) - self.ground_strength = QLabel() - summary.addWidget(self.ground_strength, 1, 1) - - economy = QLabel("Economic strength:") - summary.addWidget(economy, 2, 0) - self.economic_strength = QLabel() - summary.addWidget(self.economic_strength, 2, 1) - - self.details = QPushButton() - self.details.setMinimumHeight(50) - self.details.setMinimumWidth(210) - self.details.setLayout(summary) - columns.addWidget(self.details) - self.details.clicked.connect(self.open_details_window) - self.details.setEnabled(False) - - self.update_summary() - - self.details_window: Optional[IntelWindow] = None - - def set_game(self, game: Optional[Game]) -> None: - self.game = game - self.details.setEnabled(True) - self.update_summary() - - @staticmethod - def forces_strength_text(own: int, enemy: int) -> str: - if not enemy: - return "enemy eliminated" - - ratio = own / enemy - if ratio < 0.6: - return "outnumbered" - if ratio < 0.8: - return "slightly outnumbered" - if ratio < 1.2: - return "evenly matched" - if ratio < 1.4: - return "slight advantage" - return "strong advantage" - - def economic_strength_text(self) -> str: - assert self.game is not None - own = Income(self.game, player=True).total - enemy = Income(self.game, player=False).total - - if not enemy: - return "enemy economy ruined" - - ratio = own / enemy - if ratio < 0.6: - return "strong disadvantage" - if ratio < 0.8: - return "slight disadvantage" - if ratio < 1.2: - return "evenly matched" - if ratio < 1.4: - return "slight advantage" - return "strong advantage" - - def update_summary(self) -> None: - if self.game is None: - self.air_strength.setText("no data") - self.ground_strength.setText("no data") - self.economic_strength.setText("no data") - return - - data = self.game.game_stats.data_per_turn[-1] - - self.air_strength.setText( - self.forces_strength_text( - data.allied_units.aircraft_count, data.enemy_units.aircraft_count - ) - ) - self.ground_strength.setText( - self.forces_strength_text( - data.allied_units.vehicles_count, data.enemy_units.vehicles_count - ) - ) - self.economic_strength.setText(self.economic_strength_text()) - - if self.game.turn == 0: - self.air_strength.setText("gathering intel") - self.ground_strength.setText("gathering intel") - - def open_details_window(self) -> None: - self.details_window = IntelWindow(self.game) - self.details_window.show() diff --git a/qt_ui/widgets/QLabeledWidget.py b/qt_ui/widgets/QLabeledWidget.py deleted file mode 100644 index aa357c0b5..000000000 --- a/qt_ui/widgets/QLabeledWidget.py +++ /dev/null @@ -1,25 +0,0 @@ -"""A layout containing a widget with an associated label.""" -from typing import Optional - -from PySide6.QtCore import Qt -from PySide6.QtWidgets import QHBoxLayout, QLabel, QWidget - - -class QLabeledWidget(QHBoxLayout): - """A layout containing a widget with an associated label. - - Best used for vertical forms, where the given widget is the input and the - label is used to name the input. - """ - - def __init__( - self, text: str, widget: QWidget, tooltip: Optional[str] = None - ) -> None: - super().__init__() - label = QLabel(text) - self.addWidget(label) - self.addStretch() - self.addWidget(widget, alignment=Qt.AlignRight) - if tooltip is not None: - label.setToolTip(tooltip) - widget.setToolTip(tooltip) diff --git a/qt_ui/widgets/QLiberationCalendar.py b/qt_ui/widgets/QLiberationCalendar.py deleted file mode 100644 index a839a430d..000000000 --- a/qt_ui/widgets/QLiberationCalendar.py +++ /dev/null @@ -1,40 +0,0 @@ -from PySide6 import QtCore, QtGui -from PySide6.QtWidgets import QCalendarWidget - - -class QLiberationCalendar(QCalendarWidget): - def __init__(self, parent=None): - super(QLiberationCalendar, self).__init__(parent) - self.setVerticalHeaderFormat(QCalendarWidget.NoVerticalHeader) - self.setGridVisible(False) - - # Overrride default QCalendar behaviour that is rendering week end days in red - for d in ( - QtCore.Qt.Monday, - QtCore.Qt.Tuesday, - QtCore.Qt.Wednesday, - QtCore.Qt.Thursday, - QtCore.Qt.Friday, - QtCore.Qt.Saturday, - QtCore.Qt.Sunday, - ): - fmt = self.weekdayTextFormat(d) - fmt.setForeground(QtCore.Qt.darkGray) - self.setWeekdayTextFormat(d, fmt) - - def paintCell(self, painter, rect, date): - if date == self.selectedDate(): - painter.save() - painter.fillRect(rect, QtGui.QColor("#D3D3D3")) - painter.setPen(QtCore.Qt.NoPen) - painter.setBrush(QtGui.QColor(52, 68, 85)) - r = QtCore.QRect( - QtCore.QPoint(), min(rect.width(), rect.height()) * QtCore.QSize(1, 1) - ) - r.moveCenter(rect.center()) - painter.drawEllipse(r) - painter.setPen(QtGui.QPen(QtGui.QColor("white"))) - painter.drawText(rect, QtCore.Qt.AlignCenter, str(date.day())) - painter.restore() - else: - super(QLiberationCalendar, self).paintCell(painter, rect, date) diff --git a/qt_ui/widgets/QTopPanel.py b/qt_ui/widgets/QTopPanel.py deleted file mode 100644 index 599422554..000000000 --- a/qt_ui/widgets/QTopPanel.py +++ /dev/null @@ -1,326 +0,0 @@ -import textwrap -from datetime import datetime -from typing import List, Optional, Callable - -from PySide6.QtWidgets import ( - QDialog, - QFrame, - QGroupBox, - QHBoxLayout, - QMessageBox, - QPushButton, -) - -import qt_ui.uiconstants as CONST -from game import Game, persistence -from game.ato.package import Package -from game.ato.traveltime import TotEstimator -from game.profiling import logged_duration -from game.utils import meters -from qt_ui.models import GameModel -from qt_ui.simcontroller import SimController -from qt_ui.uiflags import UiFlags -from qt_ui.widgets.QBudgetBox import QBudgetBox -from qt_ui.widgets.QConditionsWidget import QConditionsWidget -from qt_ui.widgets.QFactionsInfos import QFactionsInfos -from qt_ui.widgets.QIntelBox import QIntelBox -from qt_ui.widgets.clientslots import MaxPlayerCount -from qt_ui.widgets.simspeedcontrols import SimSpeedControls -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow - - -class QTopPanel(QFrame): - def __init__( - self, - game_model: GameModel, - sim_controller: SimController, - ui_flags: UiFlags, - reset_to_pre_sim_checkpoint: Callable[[], None], - ) -> None: - super(QTopPanel, self).__init__() - self.game_model = game_model - self.sim_controller = sim_controller - self.reset_to_pre_sim_checkpoint = reset_to_pre_sim_checkpoint - self.dialog: Optional[QDialog] = None - - self.setMaximumHeight(70) - - self.conditionsWidget = QConditionsWidget(sim_controller) - self.budgetBox = QBudgetBox(self.game) - - pass_turn_text = "Pass Turn" - if not self.game or self.game.turn == 0: - pass_turn_text = "Begin Campaign" - self.passTurnButton = QPushButton(pass_turn_text) - self.passTurnButton.setIcon(CONST.ICONS["PassTurn"]) - self.passTurnButton.setProperty("style", "btn-primary") - self.passTurnButton.clicked.connect(self.passTurn) - if not self.game: - self.passTurnButton.setEnabled(False) - - self.proceedButton = QPushButton("Take off") - self.proceedButton.setIcon(CONST.ICONS["Proceed"]) - self.proceedButton.setProperty("style", "start-button") - self.proceedButton.clicked.connect(self.launch_mission) - if not self.game or self.game.turn == 0: - self.proceedButton.setEnabled(False) - - self.factionsInfos = QFactionsInfos(self.game) - - self.intel_box = QIntelBox(self.game) - - self.proceedBox = QGroupBox("Proceed") - self.proceedBoxLayout = QHBoxLayout() - if ui_flags.show_sim_speed_controls: - self.proceedBoxLayout.addLayout(SimSpeedControls(sim_controller)) - self.proceedBoxLayout.addLayout(MaxPlayerCount(self.game_model.ato_model)) - self.proceedBoxLayout.addWidget(self.passTurnButton) - self.proceedBoxLayout.addWidget(self.proceedButton) - self.proceedBox.setLayout(self.proceedBoxLayout) - - self.layout = QHBoxLayout() - - self.layout.addWidget(self.factionsInfos) - self.layout.addWidget(self.conditionsWidget) - self.layout.addWidget(self.budgetBox) - self.layout.addWidget(self.intel_box) - self.layout.addStretch(1) - self.layout.addWidget(self.proceedBox) - - self.layout.setContentsMargins(0, 0, 0, 0) - - self.setLayout(self.layout) - - GameUpdateSignal.get_instance().gameupdated.connect(self.setGame) - GameUpdateSignal.get_instance().budgetupdated.connect(self.budget_update) - - @property - def game(self) -> Optional[Game]: - return self.game_model.game - - def setGame(self, game: Optional[Game]): - if game is None: - return - - self.conditionsWidget.setCurrentTurn(game.turn, game.conditions) - - if game.conditions.weather.clouds: - base_m = game.conditions.weather.clouds.base - base_ft = int(meters(base_m).feet) - self.conditionsWidget.setToolTip(f"Cloud Base: {base_m}m / {base_ft}ft") - else: - self.conditionsWidget.setToolTip("") - - self.intel_box.set_game(game) - self.budgetBox.setGame(game) - self.factionsInfos.setGame(game) - - self.passTurnButton.setEnabled(True) - if game and game.turn > 0: - self.passTurnButton.setText("Pass Turn") - - if game and game.turn == 0: - self.passTurnButton.setText("Begin Campaign") - self.proceedButton.setEnabled(False) - else: - self.proceedButton.setEnabled(True) - - def passTurn(self): - with logged_duration("Skipping turn"): - self.game.pass_turn(no_action=True) - GameUpdateSignal.get_instance().updateGame(self.game) - self.proceedButton.setEnabled(True) - - def negative_start_packages(self, now: datetime) -> List[Package]: - packages = [] - for package in self.game_model.ato_model.ato.packages: - if not package.flights: - continue - for flight in package.flights: - if flight.state.is_waiting_for_start: - startup = flight.flight_plan.startup_time() - if startup < now: - packages.append(package) - break - return packages - - @staticmethod - def fix_tots(packages: List[Package], now: datetime) -> None: - for package in packages: - estimator = TotEstimator(package) - package.time_over_target = estimator.earliest_tot(now) - - def ato_has_clients(self) -> bool: - for package in self.game.blue.ato.packages: - for flight in package.flights: - if flight.client_count > 0: - return True - return False - - def confirm_no_client_launch(self) -> bool: - result = QMessageBox.question( - self, - "Continue without player pilots?", - ( - "No player pilots have been assigned to flights. Continuing will allow " - "the AI to perform the mission, but players will be unable to " - "participate.
" - "
" - "To assign player pilots to a flight, select a package from the " - "Packages panel on the left of the main window, and then a flight from " - "the Flights panel below the Packages panel. The edit button below the " - "Flights panel will allow you to assign specific pilots to the flight. " - "If you have no player pilots available, the checkbox next to the " - "name will convert them to a player.
" - "
Click 'Yes' to continue with an AI only mission" - "
Click 'No' if you'd like to make more changes." - ), - QMessageBox.No, - QMessageBox.Yes, - ) - return result == QMessageBox.Yes - - def confirm_negative_start_time(self, negative_starts: List[Package]) -> bool: - formatted = "
".join( - [f"{p.primary_task} {p.target.name}" for p in negative_starts] - ) - mbox = QMessageBox( - QMessageBox.Question, - "Continue with past start times?", - ( - "Some flights in the following packages have start times set " - "earlier than mission start time:
" - "
" - f"{formatted}
" - "
" - "Flight start times are estimated based on the package TOT, so it " - "is possible that not all flights will be able to reach the " - "target area at their assigned times.
" - "
" - "You can either continue with the mission as planned, with the " - "misplanned flights potentially flying too fast and/or missing " - "their rendezvous; automatically fix negative TOTs; or cancel " - "mission start and fix the packages manually." - ), - parent=self, - ) - auto = mbox.addButton("Fix TOTs automatically", QMessageBox.ActionRole) - ignore = mbox.addButton("Continue without fixing", QMessageBox.DestructiveRole) - cancel = mbox.addButton(QMessageBox.Cancel) - mbox.setEscapeButton(cancel) - mbox.exec_() - clicked = mbox.clickedButton() - if clicked == auto: - self.fix_tots(negative_starts, self.sim_controller.current_time_in_sim) - return True - elif clicked == ignore: - return True - return False - - def check_no_missing_pilots(self) -> bool: - missing_pilots = [] - for package in self.game.blue.ato.packages: - for flight in package.flights: - if flight.missing_pilots > 0: - missing_pilots.append((package, flight)) - - if not missing_pilots: - return False - - formatted = "
".join( - [f"{p.primary_task} {p.target}: {f}" for p, f in missing_pilots] - ) - mbox = QMessageBox( - QMessageBox.Critical, - "Flights are missing pilots", - ( - "The following flights are missing one or more pilots:
" - "
" - f"{formatted}
" - "
" - "You must either assign pilots to those flights or cancel those " - "missions." - ), - parent=self, - ) - mbox.setEscapeButton(mbox.addButton(QMessageBox.Close)) - mbox.exec_() - return True - - def check_valid_autoresolve_settings(self) -> bool: - if not self.game.settings.fast_forward_to_first_contact: - return True - - if not self.game.settings.auto_resolve_combat: - return True - - has_clients = self.ato_has_clients() - if ( - has_clients - and self.game.settings.player_mission_interrupts_sim_at is not None - ): - return True - - if has_clients: - message = textwrap.dedent( - """\ - You have enabled settings to fast forward and to auto-resolve combat, - but have not selected any interrupt condition. Fast forward will never - stop with your current settings. To use auto- resolve, you must choose a - "Player missions interrupt fast forward" setting other than "Never". - """ - ) - else: - message = textwrap.dedent( - """\ - You have enabled settings to fast forward and to auto-resolve combat, - but have no players. Fast forward will never stop with your current - settings. Auto-resolve and fast forward cannot be used without player - flights and a "Player missions interrupt fast forward" setting other - than "Never". - """ - ) - - mbox = QMessageBox( - QMessageBox.Icon.Critical, - "Incompatible fast-forward settings", - message, - parent=self, - ) - mbox.setEscapeButton(mbox.addButton(QMessageBox.StandardButton.Close)) - mbox.exec() - return False - - def launch_mission(self): - """Finishes planning and waits for mission completion.""" - if not self.ato_has_clients() and not self.confirm_no_client_launch(): - return - - if self.check_no_missing_pilots(): - return - - negative_starts = self.negative_start_packages( - self.sim_controller.current_time_in_sim - ) - if negative_starts: - if not self.confirm_negative_start_time(negative_starts): - return - - if not self.check_valid_autoresolve_settings(): - return - - if self.game.settings.fast_forward_to_first_contact: - with logged_duration("Simulating to first contact"): - self.sim_controller.run_to_first_contact() - self.sim_controller.generate_miz( - persistence.mission_path_for("liberation_nextturn.miz") - ) - - waiting = QWaitingForMissionResultWindow( - self.game, self.sim_controller, self.reset_to_pre_sim_checkpoint, self - ) - waiting.exec_() - - def budget_update(self, game: Game): - self.budgetBox.setGame(game) diff --git a/qt_ui/widgets/ato.py b/qt_ui/widgets/ato.py deleted file mode 100644 index 0b7b28362..000000000 --- a/qt_ui/widgets/ato.py +++ /dev/null @@ -1,439 +0,0 @@ -"""Widgets for displaying air tasking orders.""" -import logging -from typing import Optional - -from PySide6.QtCore import ( - QItemSelectionModel, - QModelIndex, - QSize, - Qt, -) -from PySide6.QtGui import QAction, QContextMenuEvent -from PySide6.QtWidgets import ( - QAbstractItemView, - QGroupBox, - QHBoxLayout, - QLabel, - QListView, - QMenu, - QPushButton, - QSplitter, - QVBoxLayout, -) - -from game.ato.flight import Flight -from game.ato.package import Package -from game.server import EventStream -from game.sim import GameUpdateEvents -from ..delegates import TwoColumnRowDelegate -from ..models import AtoModel, GameModel, NullListModel, PackageModel - - -class FlightDelegate(TwoColumnRowDelegate): - def __init__(self, package: Package) -> None: - super().__init__(rows=3, columns=2, font_size=10) - self.package = package - - @staticmethod - def flight(index: QModelIndex) -> Flight: - return index.data(PackageModel.FlightRole) - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - flight = self.flight(index) - if (row, column) == (0, 0): - return f"{flight}" - elif (row, column) == (0, 1): - clients = self.num_clients(index) - return f"Player Slots: {clients}" if clients else "" - elif (row, column) == (1, 0): - origin = flight.departure.name - if flight.arrival != flight.departure: - return f"From {origin} to {flight.arrival.name}" - return f"From {origin}" - elif (row, column) == (1, 1): - missing_pilots = flight.missing_pilots - return f"Missing pilots: {flight.missing_pilots}" if missing_pilots else "" - elif (row, column) == (2, 0): - return flight.state.description.title() - return "" - - def num_clients(self, index: QModelIndex) -> int: - flight = self.flight(index) - return flight.client_count - - -class QFlightList(QListView): - """List view for displaying the flights of a package.""" - - def __init__( - self, game_model: GameModel, package_model: Optional[PackageModel] - ) -> None: - super().__init__() - self.game_model = game_model - self.package_model = package_model - self.set_package(package_model) - if package_model is not None: - self.setItemDelegate(FlightDelegate(package_model.package)) - self.setIconSize(QSize(91, 24)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - self.doubleClicked.connect(self.on_double_click) - - def set_package(self, model: Optional[PackageModel]) -> None: - """Sets the package model to display.""" - if model is None: - self.disconnect_model() - else: - self.package_model = model - self.setItemDelegate(FlightDelegate(model.package)) - self.setModel(model) - # noinspection PyUnresolvedReferences - model.deleted.connect(self.disconnect_model) - self.selectionModel().setCurrentIndex( - model.index(0, 0, QModelIndex()), QItemSelectionModel.Select - ) - - def disconnect_model(self) -> None: - """Clears the listview of any model attachments. - - Displays an empty list until set_package is called with a valid model. - """ - model = self.model() - if model is not None and isinstance(model, PackageModel): - model.deleted.disconnect(self.disconnect_model) - self.setModel(NullListModel()) - - @property - def selected_item(self) -> Optional[Flight]: - """Returns the selected flight, if any.""" - index = self.currentIndex() - if not index.isValid(): - return None - return self.package_model.flight_at_index(index) - - def on_double_click(self, index: QModelIndex) -> None: - if not index.isValid(): - return - self.edit_flight(index) - - def edit_flight(self, index: QModelIndex) -> None: - from qt_ui.dialogs import Dialog - - Dialog.open_edit_flight_dialog( - self.package_model, - self.package_model.flight_at_index(index), - parent=self.window(), - ) - - def cancel_or_abort_flight(self, index: QModelIndex) -> None: - self.package_model.cancel_or_abort_flight_at_index(index) - - def contextMenuEvent(self, event: QContextMenuEvent) -> None: - index = self.indexAt(event.pos()) - - menu = QMenu("Menu") - - edit_action = QAction("Edit") - edit_action.triggered.connect(lambda: self.edit_flight(index)) - menu.addAction(edit_action) - - delete_action = QAction(f"Delete") - delete_action.triggered.connect(lambda: self.cancel_or_abort_flight(index)) - menu.addAction(delete_action) - - menu.exec_(event.globalPos()) - - -class QFlightPanel(QGroupBox): - """The flight display portion of the ATO panel. - - Displays the flights assigned to the selected package, and includes edit and - delete buttons for flight management. - """ - - def __init__( - self, game_model: GameModel, package_model: Optional[PackageModel] = None - ) -> None: - super().__init__("Flights") - self.game_model = game_model - self.package_model = package_model - - self.vbox = QVBoxLayout() - self.setLayout(self.vbox) - - self.tip = QLabel( - "To add flights to a package, edit the package by double clicking " - "it or pressing the edit button." - ) - self.vbox.addWidget(self.tip) - - self.flight_list = QFlightList(game_model, package_model) - self.vbox.addWidget(self.flight_list) - - self.button_row = QHBoxLayout() - self.vbox.addLayout(self.button_row) - - self.edit_button = QPushButton("Edit") - self.edit_button.clicked.connect(self.on_edit) - self.button_row.addWidget(self.edit_button) - - self.delete_button = QPushButton("Cancel") - # noinspection PyTypeChecker - self.delete_button.setProperty("style", "btn-danger") - self.delete_button.clicked.connect(self.on_cancel_flight) - self.button_row.addWidget(self.delete_button) - - self.selection_changed.connect(self.on_selection_changed) - self.on_selection_changed() - - def set_package(self, model: Optional[PackageModel]) -> None: - """Sets the package model to display.""" - self.package_model = model - self.flight_list.set_package(model) - self.selection_changed.connect(self.on_selection_changed) - self.on_selection_changed() - - @property - def selection_changed(self): - """Returns the signal emitted when the flight selection changes.""" - return self.flight_list.selectionModel().selectionChanged - - def on_selection_changed(self) -> None: - """Updates the status of the edit and delete buttons.""" - index = self.flight_list.currentIndex() - enabled = index.isValid() - self.edit_button.setEnabled(enabled) - self.delete_button.setEnabled(enabled) - self.change_map_flight_selection(index) - delete_text = "Cancel" - if (flight := self.flight_list.selected_item) is not None: - if not flight.state.cancelable: - delete_text = "Abort" - self.delete_button.setText(delete_text) - - def change_map_flight_selection(self, index: QModelIndex) -> None: - events = GameUpdateEvents() - if not index.isValid(): - events.deselect_flight() - else: - events.select_flight(self.package_model.flight_at_index(index)) - EventStream.put_nowait(events) - - def on_edit(self) -> None: - """Opens the flight edit dialog.""" - index = self.flight_list.currentIndex() - if not index.isValid(): - logging.error(f"Cannot edit flight when no flight is selected.") - return - self.flight_list.edit_flight(index) - - def on_cancel_flight(self) -> None: - """Removes the selected flight from the package.""" - index = self.flight_list.currentIndex() - if not index.isValid(): - logging.error(f"Cannot delete flight when no flight is selected.") - return - self.flight_list.cancel_or_abort_flight(index) - - -class PackageDelegate(TwoColumnRowDelegate): - def __init__(self, game_model: GameModel) -> None: - super().__init__(rows=2, columns=2) - self.game_model = game_model - - @staticmethod - def package(index: QModelIndex) -> Package: - return index.data(AtoModel.PackageRole) - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - package = self.package(index) - if (row, column) == (0, 0): - return f"{package.package_description} {package.target.name}" - elif (row, column) == (0, 1): - clients = self.num_clients(index) - return f"Player Slots: {clients}" if clients else "" - elif (row, column) == (1, 0): - return f"TOT at {package.time_over_target:%H:%M:%S}" - elif (row, column) == (1, 1): - unassigned_pilots = self.missing_pilots(index) - return f"Missing pilots: {unassigned_pilots}" if unassigned_pilots else "" - return "" - - def num_clients(self, index: QModelIndex) -> int: - package = self.package(index) - return sum(f.client_count for f in package.flights) - - def missing_pilots(self, index: QModelIndex) -> int: - package = self.package(index) - return sum(f.missing_pilots for f in package.flights) - - -class QPackageList(QListView): - """List view for displaying the packages of an ATO.""" - - def __init__(self, game_model: GameModel, model: AtoModel) -> None: - super().__init__() - self.ato_model = model - self.setModel(model) - self.setItemDelegate(PackageDelegate(game_model)) - self.setIconSize(QSize(0, 0)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - self.model().rowsInserted.connect(self.on_new_packages) - self.doubleClicked.connect(self.on_double_click) - - @property - def selected_item(self) -> Optional[Package]: - """Returns the selected package, if any.""" - index = self.currentIndex() - if not index.isValid(): - return None - return self.ato_model.package_at_index(index) - - def edit_package(self, index: QModelIndex) -> None: - from qt_ui.dialogs import Dialog - - Dialog.open_edit_package_dialog(self.ato_model.get_package_model(index)) - - def delete_package(self, index: QModelIndex) -> None: - self.ato_model.cancel_or_abort_package_at_index(index) - - def on_new_packages(self, _parent: QModelIndex, first: int, _last: int) -> None: - # Select the newly created pacakges. This should only ever happen due to - # the player saving a new package, so selecting it helps them view/edit - # it faster. - self.selectionModel().setCurrentIndex( - self.model().index(first, 0), QItemSelectionModel.Select - ) - - def on_double_click(self, index: QModelIndex) -> None: - if not index.isValid(): - return - self.edit_package(index) - - def contextMenuEvent(self, event: QContextMenuEvent) -> None: - index = self.indexAt(event.pos()) - - menu = QMenu("Menu") - - edit_action = QAction("Edit") - edit_action.triggered.connect(lambda: self.edit_package(index)) - menu.addAction(edit_action) - - delete_action = QAction(f"Delete") - delete_action.triggered.connect(lambda: self.delete_package(index)) - menu.addAction(delete_action) - - menu.exec_(event.globalPos()) - - -class QPackagePanel(QGroupBox): - """The package display portion of the ATO panel. - - Displays the package assigned to the player's ATO, and includes edit and - delete buttons for package management. - """ - - def __init__(self, game_model: GameModel, ato_model: AtoModel) -> None: - super().__init__("Packages") - self.ato_model = ato_model - self.ato_model.layoutChanged.connect(self.on_current_changed) - - self.vbox = QVBoxLayout() - self.setLayout(self.vbox) - - self.tip = QLabel( - "To create a new package, right click the mission target on the " - "map. To target airbase objectives, use\n" - "the attack button in the airbase view." - ) - self.vbox.addWidget(self.tip) - - self.package_list = QPackageList(game_model, self.ato_model) - self.vbox.addWidget(self.package_list) - - self.button_row = QHBoxLayout() - self.vbox.addLayout(self.button_row) - - self.edit_button = QPushButton("Edit") - self.edit_button.clicked.connect(self.on_edit) - self.button_row.addWidget(self.edit_button) - - self.delete_button = QPushButton("Cancel/abort") - # noinspection PyTypeChecker - self.delete_button.setProperty("style", "btn-danger") - self.delete_button.clicked.connect(self.on_delete) - self.button_row.addWidget(self.delete_button) - - self.current_changed.connect(self.on_current_changed) - self.on_current_changed() - - @property - def current_changed(self): - """Returns the signal emitted when the flight selection changes.""" - return self.package_list.selectionModel().currentChanged - - def on_current_changed(self) -> None: - """Updates the status of the edit and delete buttons.""" - index = self.package_list.currentIndex() - enabled = index.isValid() - self.edit_button.setEnabled(enabled) - self.delete_button.setEnabled(enabled) - self.change_map_package_selection(index) - - def change_map_package_selection(self, index: QModelIndex) -> None: - if not index.isValid(): - EventStream.put_nowait(GameUpdateEvents().deselect_flight()) - return - - package = self.ato_model.get_package_model(index) - if package.rowCount() == 0: - EventStream.put_nowait(GameUpdateEvents().deselect_flight()) - else: - EventStream.put_nowait( - GameUpdateEvents().select_flight( - package.flight_at_index(package.index(0)) - ) - ) - - def on_edit(self) -> None: - """Opens the package edit dialog.""" - index = self.package_list.currentIndex() - if not index.isValid(): - logging.error(f"Cannot edit package when no package is selected.") - return - self.package_list.edit_package(index) - - def on_delete(self) -> None: - """Removes the package from the ATO.""" - index = self.package_list.currentIndex() - if not index.isValid(): - logging.error(f"Cannot delete package when no package is selected.") - return - self.package_list.delete_package(index) - - -class QAirTaskingOrderPanel(QSplitter): - """A split panel for displaying the packages and flights of an ATO. - - Used as the left-bar of the main UI. The top half of the panel displays the - packages of the player's ATO, and the bottom half displays the flights of - the selected package. - """ - - def __init__(self, game_model: GameModel) -> None: - super().__init__(Qt.Vertical) - self.ato_model = game_model.ato_model - - self.package_panel = QPackagePanel(game_model, self.ato_model) - self.package_panel.current_changed.connect(self.on_package_change) - self.addWidget(self.package_panel) - - self.flight_panel = QFlightPanel(game_model) - self.addWidget(self.flight_panel) - - def on_package_change(self) -> None: - """Sets the newly selected flight for display in the bottom panel.""" - index = self.package_panel.package_list.currentIndex() - if index.isValid(): - self.flight_panel.set_package(self.ato_model.get_package_model(index)) - else: - self.flight_panel.set_package(None) diff --git a/qt_ui/widgets/clientslots.py b/qt_ui/widgets/clientslots.py deleted file mode 100644 index 5af9fd104..000000000 --- a/qt_ui/widgets/clientslots.py +++ /dev/null @@ -1,31 +0,0 @@ -"""Widgets for displaying client slots.""" -from PySide6.QtWidgets import QLabel - -from qt_ui.models import AtoModel -from qt_ui.widgets.QLabeledWidget import QLabeledWidget - - -class MaxPlayerCount(QLabeledWidget): - def __init__(self, ato_model: AtoModel) -> None: - self.ato_model = ato_model - self.slots_label = QLabel(str(self.count_client_slots)) - self.ato_model.client_slots_changed.connect(self.update_count) - super().__init__( - "Max Players:", - self.slots_label, - ( - "Total number of client slots. To add client slots, edit a flight " - "using the panel on the left." - ), - ) - - @property - def count_client_slots(self) -> int: - slots = 0 - for package in self.ato_model.packages: - for flight in package.flights: - slots += flight.client_count - return slots - - def update_count(self) -> None: - self.slots_label.setText(str(self.count_client_slots)) diff --git a/qt_ui/widgets/combos/QAircraftTypeSelector.py b/qt_ui/widgets/combos/QAircraftTypeSelector.py deleted file mode 100644 index 41afa1f7a..000000000 --- a/qt_ui/widgets/combos/QAircraftTypeSelector.py +++ /dev/null @@ -1,26 +0,0 @@ -"""Combo box for selecting aircraft types.""" -from PySide6.QtWidgets import QComboBox - -from game.dcs.aircrafttype import AircraftType - - -class QAircraftTypeSelector(QComboBox): - """Combo box for selecting among the given aircraft types.""" - - def __init__(self, aircraft_types: list[AircraftType]) -> None: - super().__init__() - - self.model().sort(0) - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.update_items(aircraft_types) - - def update_items(self, aircraft_types: list[AircraftType]): - current_aircraft = self.currentData() - self.clear() - for aircraft in aircraft_types: - self.addItem(f"{aircraft}", userData=aircraft) - current_aircraft_index = self.findData(current_aircraft) - if current_aircraft_index != -1: - self.setCurrentIndex(current_aircraft_index) - if self.count() == 0: - self.addItem("No capable aircraft available", userData=None) diff --git a/qt_ui/widgets/combos/QArrivalAirfieldSelector.py b/qt_ui/widgets/combos/QArrivalAirfieldSelector.py deleted file mode 100644 index 02215603f..000000000 --- a/qt_ui/widgets/combos/QArrivalAirfieldSelector.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Combo box for selecting a departure airfield.""" -from typing import Iterable, Optional - -from PySide6.QtWidgets import QComboBox -from dcs.unittype import FlyingType - -from game.dcs.aircrafttype import AircraftType -from game.theater.controlpoint import ControlPoint - - -class QArrivalAirfieldSelector(QComboBox): - """A combo box for selecting a flight's arrival or divert airfield. - - The combo box will automatically be populated with all airfields the given - aircraft type is able to land at. - """ - - def __init__( - self, - destinations: Iterable[ControlPoint], - aircraft: Optional[AircraftType], - optional_text: str, - ) -> None: - super().__init__() - self.destinations = list(destinations) - self.aircraft = aircraft - self.optional_text = optional_text - self.rebuild_selector() - self.setCurrentIndex(0) - - def change_aircraft(self, aircraft: Optional[FlyingType]) -> None: - if self.aircraft == aircraft: - return - self.aircraft = aircraft - self.rebuild_selector() - - def rebuild_selector(self) -> None: - self.clear() - if self.aircraft is None: - return - for destination in self.destinations: - if destination.can_operate(self.aircraft): - self.addItem(destination.name, destination) - self.model().sort(0) - self.insertItem(0, self.optional_text, None) - self.setCurrentIndex(0) diff --git a/qt_ui/widgets/combos/QFilteredComboBox.py b/qt_ui/widgets/combos/QFilteredComboBox.py deleted file mode 100644 index 65d7a940c..000000000 --- a/qt_ui/widgets/combos/QFilteredComboBox.py +++ /dev/null @@ -1,61 +0,0 @@ -from PySide6.QtCore import QSortFilterProxyModel, Qt -from PySide6.QtWidgets import QComboBox, QCompleter - - -class QFilteredComboBox(QComboBox): - def __init__( - self, - parent=None, - include_targets=True, - include_airbases=True, - include_frontlines=True, - include_units=True, - include_enemy=True, - include_friendly=True, - ): - super(QFilteredComboBox, self).__init__(parent) - - self.setFocusPolicy(Qt.StrongFocus) - self.setEditable(True) - self.completer = QCompleter(self) - - self.include_targets = include_targets - self.include_airbases = include_airbases - self.include_frontlines = include_frontlines - self.include_units = include_units - self.include_enemy = include_enemy - self.include_friendly = include_friendly - - # always show all completions - self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion) - self.pFilterModel = QSortFilterProxyModel(self) - self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive) - - self.completer.setPopup(self.view()) - - self.setCompleter(self.completer) - - self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString) - self.completer.activated.connect(self.setTextIfCompleterIsClicked) - - def setModel(self, model): - super(QFilteredComboBox, self).setModel(model) - self.pFilterModel.setSourceModel(model) - self.completer.setModel(self.pFilterModel) - self.model().sort(0) - - def setModelColumn(self, column): - self.completer.setCompletionColumn(column) - self.pFilterModel.setFilterKeyColumn(column) - super(QFilteredComboBox, self).setModelColumn(column) - - def view(self): - return self.completer.popup() - - def index(self): - return self.currentIndex() - - def setTextIfCompleterIsClicked(self, text): - if text: - index = self.findText(text) - self.setCurrentIndex(index) diff --git a/qt_ui/widgets/combos/QFlightTypeComboBox.py b/qt_ui/widgets/combos/QFlightTypeComboBox.py deleted file mode 100644 index 1d82d76f3..000000000 --- a/qt_ui/widgets/combos/QFlightTypeComboBox.py +++ /dev/null @@ -1,29 +0,0 @@ -"""Combo box for selecting a flight's task type.""" - -from PySide6.QtWidgets import QComboBox - -from game.ato.flighttype import FlightType -from game.plugins import LuaPluginManager -from game.theater import ConflictTheater, MissionTarget - - -class QFlightTypeComboBox(QComboBox): - """Combo box for selecting a flight task type.""" - - def __init__( - self, - theater: ConflictTheater, - target: MissionTarget, - lua_plugin_manager: LuaPluginManager, - ) -> None: - super().__init__() - self.theater = theater - self.target = target - for mission_type in self.target.mission_types(for_player=True): - if ( - mission_type == FlightType.AIR_ASSAULT - and not lua_plugin_manager.is_plugin_enabled("ctld") - ): - # Only add Air Assault if ctld plugin is enabled - continue - self.addItem(str(mission_type), userData=mission_type) diff --git a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py b/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py deleted file mode 100644 index 2d0955a6c..000000000 --- a/qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py +++ /dev/null @@ -1,130 +0,0 @@ -from PySide6.QtGui import QStandardItem, QStandardItemModel - -from game import Game -from game.ato.flightwaypoint import FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.missiongenerator.frontlineconflictdescription import ( - FrontLineConflictDescription, -) -from game.theater.controlpoint import ControlPointType -from game.utils import Distance -from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox - - -class QPredefinedWaypointSelectionComboBox(QFilteredComboBox): - def __init__( - self, - game: Game, - parent=None, - include_targets=True, - include_airbases=True, - include_frontlines=True, - include_units=True, - include_enemy=True, - include_friendly=True, - ): - super(QPredefinedWaypointSelectionComboBox, self).__init__(parent) - self.game = game - self.include_targets = include_targets - self.include_airbases = include_airbases - self.include_frontlines = include_frontlines - self.include_units = include_units - self.include_enemy = include_enemy - self.include_friendly = include_friendly - self.find_possible_waypoints() - - def get_selected_waypoints(self, include_all_from_same_location=False): - n = self.currentText() - first_waypoint = None - for w in self.wpts: - if w.pretty_name == n: - first_waypoint = w - break - if first_waypoint is None: - return [] - waypoints = [first_waypoint] - if include_all_from_same_location: - for w in self.wpts: - if ( - w is not first_waypoint - and w.obj_name - and w.obj_name == first_waypoint.obj_name - ): - waypoints.append(w) - return waypoints - - def find_possible_waypoints(self): - self.wpts = [] - model = QStandardItemModel() - i = 0 - - def add_model_item(i, model, name, wpt): - item = QStandardItem(name) - model.setItem(i, 0, item) - self.wpts.append(wpt) - return i + 1 - - if self.include_frontlines: - for front_line in self.game.theater.conflicts(): - pos = FrontLineConflictDescription.frontline_position( - front_line, self.game.theater - )[0] - wptname = f"Frontline {front_line.name} [CAS]" - wpt = FlightWaypoint( - wptname, FlightWaypointType.CUSTOM, pos, Distance.from_meters(800) - ) - - wpt.alt_type = "RADIO" - wpt.pretty_name = wpt.name - wpt.description = "Frontline" - i = add_model_item(i, model, wpt.pretty_name, wpt) - - for tgo in self.game.theater.ground_objects: - for target_idx, target in enumerate(tgo.strike_targets): - wptname = f"[{tgo.obj_name}] : {target.name} #{target_idx}" - wpt = FlightWaypoint( - wptname, - FlightWaypointType.CUSTOM, - target.position, - Distance.from_meters(0), - ) - wpt.alt_type = "RADIO" - wpt.pretty_name = wptname - wpt.targets.append(target) - wpt.obj_name = tgo.obj_name - wpt.waypoint_type = FlightWaypointType.CUSTOM - if tgo.is_friendly(to_player=True): - wpt.description = f"Friendly unit: {target.name}" - else: - wpt.description = f"Enemy unit: {target.name}" - i = add_model_item(i, model, wpt.pretty_name, wpt) - - if self.include_airbases: - for cp in self.game.theater.controlpoints: - if (self.include_enemy and not cp.captured) or ( - self.include_friendly and cp.captured - ): - wpt = FlightWaypoint( - cp.name, - FlightWaypointType.CUSTOM, - cp.position, - Distance.from_meters(0), - ) - wpt.alt_type = "RADIO" - if cp.captured: - wpt.description = ( - "Position of " + cp.name + " [Friendly Airbase]" - ) - else: - wpt.description = "Position of " + cp.name + " [Enemy Airbase]" - - if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP: - wpt.pretty_name = cp.name + " (Aircraft Carrier Group)" - elif cp.cptype == ControlPointType.LHA_GROUP: - wpt.pretty_name = cp.name + " (LHA Group)" - else: - wpt.pretty_name = cp.name + " (Airbase)" - - i = add_model_item(i, model, wpt.pretty_name, wpt) - - self.setModel(model) diff --git a/qt_ui/widgets/combos/liveryselector.py b/qt_ui/widgets/combos/liveryselector.py deleted file mode 100644 index b1a4c9751..000000000 --- a/qt_ui/widgets/combos/liveryselector.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -import dcs.countries -from PySide6.QtWidgets import QComboBox -from dcs.liveries.livery import Livery - -from game.squadrons import Squadron - - -class LiverySelector(QComboBox): - def __init__(self, squadron: Squadron) -> None: - super().__init__() - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.set_squadron(squadron) - - @property - def selected_livery(self) -> Livery | None: - return self.currentData() - - def set_squadron(self, squadron: Squadron) -> None: - selected_idx: int | None = None - self.clear() - self.addItem("Default", None) - for idx, livery in enumerate( - squadron.aircraft.dcs_unit_type.iter_liveries_for_country( - dcs.countries.get_by_name(squadron.country) - ), - 1, # First entry is "Default". - ): - self.addItem(livery.name, livery) - if squadron.livery == livery.id: - selected_idx = idx - if selected_idx is not None: - self.setCurrentIndex(selected_idx) - self.update() diff --git a/qt_ui/widgets/combos/primarytaskselector.py b/qt_ui/widgets/combos/primarytaskselector.py deleted file mode 100644 index 2f39b0cba..000000000 --- a/qt_ui/widgets/combos/primarytaskselector.py +++ /dev/null @@ -1,39 +0,0 @@ -from __future__ import annotations - -from PySide6.QtWidgets import QComboBox - -from game.ato import FlightType -from game.dcs.aircrafttype import AircraftType -from game.squadrons import Squadron - - -class PrimaryTaskSelector(QComboBox): - def __init__(self, aircraft: AircraftType | None) -> None: - super().__init__() - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.set_aircraft(aircraft) - - @staticmethod - def for_squadron(squadron: Squadron) -> PrimaryTaskSelector: - selector = PrimaryTaskSelector(squadron.aircraft) - selector.setCurrentText(squadron.primary_task.value) - return selector - - def set_aircraft(self, aircraft: AircraftType | None) -> None: - self.clear() - if aircraft is None: - self.addItem("Select aircraft type first", None) - self.setEnabled(False) - self.update() - return - - self.setEnabled(True) - for task in aircraft.iter_task_capabilities(): - self.addItem(task.value, task) - self.model().sort(0) - self.setEnabled(True) - self.update() - - @property - def selected_task(self) -> FlightType | None: - return self.currentData() diff --git a/qt_ui/widgets/floatspinners.py b/qt_ui/widgets/floatspinners.py deleted file mode 100644 index 95cf468a3..000000000 --- a/qt_ui/widgets/floatspinners.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Optional - -from PySide6.QtWidgets import QSpinBox - - -class FloatSpinner(QSpinBox): - def __init__( - self, - divisor: int, - minimum: Optional[float] = None, - maximum: Optional[float] = None, - initial: Optional[float] = None, - ) -> None: - super().__init__() - self.divisor = divisor - - if minimum is not None: - self.setMinimum(int(minimum * divisor)) - if maximum is not None: - self.setMaximum(int(maximum * divisor)) - if initial is not None: - self.setValue(int(initial * divisor)) - - def textFromValue(self, val: int) -> str: - return f"X {val / self.divisor:.1f}" - - @property - def real_value(self) -> float: - return self.value() / self.divisor diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py deleted file mode 100644 index c1e9e6169..000000000 --- a/qt_ui/widgets/map/QLiberationMap.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import annotations - -import logging -from pathlib import Path - -from PySide6.QtCore import QUrl -from PySide6.QtWebEngineCore import QWebEnginePage, QWebEngineSettings -from PySide6.QtWebEngineWidgets import QWebEngineView - -from game.server.settings import ServerSettings -from qt_ui.models import GameModel - - -class LoggingWebPage(QWebEnginePage): - def javaScriptConsoleMessage( - self, - level: QWebEnginePage.JavaScriptConsoleMessageLevel, - message: str, - line_number: int, - source: str, - ) -> None: - if level == QWebEnginePage.JavaScriptConsoleMessageLevel.ErrorMessageLevel: - logging.error(message) - elif level == QWebEnginePage.JavaScriptConsoleMessageLevel.WarningMessageLevel: - logging.warning(message) - else: - logging.info(message) - - -class QLiberationMap(QWebEngineView): - def __init__(self, game_model: GameModel, dev: bool, parent) -> None: - super().__init__(parent) - self.game_model = game_model - self.setMinimumSize(800, 600) - - self.page = LoggingWebPage(self) - # Required to allow "cross-origin" access from file:// scoped canvas.html to the - # localhost HTTP backend. - self.page.settings().setAttribute( - QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls, True - ) - - if dev: - url = QUrl("http://localhost:3000") - else: - url = QUrl.fromLocalFile(str(Path("client/build/index.html").resolve())) - server_settings = ServerSettings.get() - host = server_settings.server_bind_address - if host.startswith("::"): - host = f"[{host}]" - port = server_settings.server_port - url.setQuery(f"server={host}:{port}") - self.page.load(url) - self.setPage(self.page) diff --git a/qt_ui/widgets/simspeedcontrols.py b/qt_ui/widgets/simspeedcontrols.py deleted file mode 100644 index cc6308b05..000000000 --- a/qt_ui/widgets/simspeedcontrols.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from PySide6.QtCore import QSize -from PySide6.QtWidgets import QHBoxLayout, QPushButton, QSpinBox, QWidget - -from game.sim.simspeedsetting import SimSpeedSetting -from qt_ui.simcontroller import SimController - - -class SimSpeedSpinner(QSpinBox): - def __init__(self, sim_controller: SimController, parent: QWidget | None) -> None: - super().__init__(parent) - self.sim_controller = sim_controller - - # Disable text editing, which wouldn't work in the first place, but also - # obnoxiously selects the text on change (highlighting it) and leaves a flashing - # cursor in the middle of the element when clicked. - self.lineEdit().setEnabled(False) - - # The value stored by the spinner is the index of the speed setting in the enum. - # SimSpeedSetting is ordered, so the minimum value is paused, and increasing the - # value will speed up the game by one speed). - self.setMinimum(0) - self.setMaximum(len(SimSpeedSetting) - 1) - self.setValue(0) - - self.valueChanged.connect(self.on_change) - self.sim_controller.sim_speed_changed.connect(self.on_sim_speed_reset) - - @staticmethod - def speed_for_value(value: int) -> SimSpeedSetting: - return list(SimSpeedSetting)[value] - - def sizeHint(self) -> QSize: - # The default size hinting fails to deal with label width, and will truncate - # "Paused". - size = super().sizeHint() - size.setWidth(86) - return size - - def textFromValue(self, value: int) -> str: - return self.speed_for_value(value).text - - def valueFromText(self, text: str) -> int: - for idx, speed in enumerate(SimSpeedSetting): - if speed.text == text: - return idx - raise ValueError(f"Unknown SimSpeedSetting: {text}") - - def on_change(self, value: int) -> None: - self.sim_controller.set_simulation_speed(self.speed_for_value(value)) - - def on_sim_speed_reset(self, speed_setting: SimSpeedSetting) -> None: - self.setValue(list(SimSpeedSetting).index(speed_setting)) - - -class SimSpeedControls(QHBoxLayout): - def __init__( - self, sim_controller: SimController, parent: Optional[QWidget] = None - ) -> None: - super().__init__(parent) - self.sim_controller = sim_controller - - self.pause_button = QPushButton(text="Pause") - self.pause_button.clicked.connect( - lambda: self.sim_controller.set_simulation_speed(SimSpeedSetting.PAUSED) - ) - self.addWidget(self.pause_button) - - self.speed_spinner = SimSpeedSpinner(sim_controller, parent) - self.addWidget(self.speed_spinner) diff --git a/qt_ui/widgets/spinsliders.py b/qt_ui/widgets/spinsliders.py deleted file mode 100644 index 5ca2a9abe..000000000 --- a/qt_ui/widgets/spinsliders.py +++ /dev/null @@ -1,92 +0,0 @@ -from datetime import timedelta -from typing import Optional - -from PySide6 import QtWidgets -from PySide6.QtCore import Qt -from PySide6.QtWidgets import QSlider, QHBoxLayout - -from qt_ui.widgets.floatspinners import FloatSpinner - - -class FloatSpinSlider(QHBoxLayout): - def __init__( - self, minimum: float, maximum: float, initial: float, divisor: int - ) -> None: - super().__init__() - - slider = QSlider(Qt.Horizontal) - slider.setMinimum(int(minimum * divisor)) - slider.setMaximum(int(maximum * divisor)) - slider.setValue(int(initial * divisor)) - self.spinner = FloatSpinner(divisor, minimum, maximum, initial) - slider.valueChanged.connect(lambda x: self.spinner.setValue(x)) - self.spinner.valueChanged.connect(lambda x: slider.setValue(x)) - - self.addWidget(slider) - self.addWidget(self.spinner) - - @property - def value(self) -> float: - return self.spinner.real_value - - -class TimeInputs(QtWidgets.QHBoxLayout): - def __init__(self, initial: timedelta, minimum: int, maximum: int) -> None: - super().__init__() - - initial_minutes = int(initial.total_seconds() / 60) - - slider = QtWidgets.QSlider(Qt.Horizontal) - slider.setMinimum(minimum) - slider.setMaximum(maximum) - slider.setValue(initial_minutes) - self.spinner = TimeSpinner(minimum, maximum, initial_minutes) - slider.valueChanged.connect(lambda x: self.spinner.setValue(x)) - self.spinner.valueChanged.connect(lambda x: slider.setValue(x)) - - self.addWidget(slider) - self.addWidget(self.spinner) - - @property - def value(self) -> timedelta: - return timedelta(minutes=self.spinner.value()) - - -class TimeSpinner(QtWidgets.QSpinBox): - def __init__( - self, - minimum: Optional[int] = None, - maximum: Optional[int] = None, - initial: Optional[int] = None, - ) -> None: - super().__init__() - - if minimum is not None: - self.setMinimum(minimum) - if maximum is not None: - self.setMaximum(maximum) - if initial is not None: - self.setValue(initial) - - def textFromValue(self, val: int) -> str: - return f"{val} minutes" - - -class CurrencySpinner(QtWidgets.QSpinBox): - def __init__( - self, - minimum: Optional[int] = None, - maximum: Optional[int] = None, - initial: Optional[int] = None, - ) -> None: - super().__init__() - - if minimum is not None: - self.setMinimum(minimum) - if maximum is not None: - self.setMaximum(maximum) - if initial is not None: - self.setValue(initial) - - def textFromValue(self, val: int) -> str: - return f"${val}" diff --git a/qt_ui/windows/AirWingConfigurationDialog.py b/qt_ui/windows/AirWingConfigurationDialog.py deleted file mode 100644 index 89bafac04..000000000 --- a/qt_ui/windows/AirWingConfigurationDialog.py +++ /dev/null @@ -1,1037 +0,0 @@ -import textwrap -from collections import defaultdict -from typing import Iterable, Iterator, Optional - -from PySide6.QtCore import ( - QItemSelection, - QItemSelectionModel, - QSize, - Qt, - Signal, -) -from PySide6.QtGui import QIcon, QStandardItem, QStandardItemModel -from PySide6.QtWidgets import ( - QCheckBox, - QComboBox, - QDialog, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QLineEdit, - QListView, - QMessageBox, - QPushButton, - QScrollArea, - QStackedLayout, - QTabWidget, - QTextEdit, - QToolButton, - QVBoxLayout, - QWidget, - QSpinBox, -) - -from game import Game -from game.ato.flighttype import FlightType -from game.campaignloader.campaignairwingconfig import DEFAULT_SQUADRON_SIZE -from game.coalition import Coalition -from game.dcs.aircrafttype import AircraftType -from game.squadrons import AirWing, Pilot, Squadron -from game.squadrons.squadrondef import SquadronDef -from game.theater import ControlPoint -from qt_ui.uiconstants import AIRCRAFT_ICONS, ICONS -from qt_ui.widgets.combos.liveryselector import LiverySelector -from qt_ui.widgets.combos.primarytaskselector import PrimaryTaskSelector - - -class QMissionType(QCheckBox): - def __init__( - self, mission_type: FlightType, allowed: bool, auto_assignable: bool - ) -> None: - super().__init__() - self.flight_type = mission_type - self.setEnabled(allowed) - self.setChecked(auto_assignable) - - @property - def auto_assignable(self) -> bool: - return self.isChecked() - - -class MissionTypeControls(QGridLayout): - def __init__(self, squadron: Squadron) -> None: - super().__init__() - self.squadron = squadron - self.mission_types: list[QMissionType] = [] - - self.addWidget(QLabel("Mission Type"), 0, 0) - self.addWidget(QLabel("Auto-Assign"), 0, 1) - - for i, task in enumerate(FlightType): - if task is FlightType.FERRY: - # Not plannable so just skip it. - continue - auto_assignable = task in squadron.auto_assignable_mission_types - mission_type = QMissionType( - task, squadron.capable_of(task), auto_assignable - ) - self.mission_types.append(mission_type) - - self.addWidget(QLabel(task.value), i + 1, 0) - self.addWidget(mission_type, i + 1, 1) - - @property - def auto_assignable_mission_types(self) -> Iterator[FlightType]: - for mission_type in self.mission_types: - if mission_type.auto_assignable: - yield mission_type.flight_type - - def replace_squadron(self, squadron: Squadron) -> None: - self.squadron = squadron - for mission_type in self.mission_types: - mission_type.setChecked( - mission_type.flight_type in self.squadron.auto_assignable_mission_types - ) - - -class SquadronBaseSelector(QComboBox): - """A combo box for selecting a squadrons home air base. - - The combo box will automatically be populated with all air bases compatible with the - squadron. - """ - - def __init__( - self, - bases: Iterable[ControlPoint], - selected_base: Optional[ControlPoint], - aircraft_type: Optional[AircraftType], - ) -> None: - super().__init__() - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.bases = list(bases) - self.set_aircraft_type(aircraft_type) - - if selected_base: - self.setCurrentText(selected_base.name) - # TODO can we get a prefered base if none is selected? - - def set_aircraft_type(self, aircraft_type: Optional[AircraftType]): - self.clear() - if aircraft_type: - for base in self.bases: - if not base.can_operate(aircraft_type): - continue - self.addItem(base.name, base) - self.model().sort(0) - self.setEnabled(True) - else: - self.addItem("Select aircraft type first", None) - self.setEnabled(False) - self.update() - - -class SquadronSizeSpinner(QSpinBox): - def __init__(self, starting_size: int, parent: QWidget | None) -> None: - super().__init__(parent) - - # Disable text editing, which wouldn't work in the first place, but also - # obnoxiously selects the text on change (highlighting it) and leaves a flashing - # cursor in the middle of the element when clicked. - self.lineEdit().setEnabled(False) - - self.setMinimum(1) - self.setValue(starting_size) - - # def sizeHint(self) -> QSize: - # # The default size hinting fails to deal with label width, and will truncate - # # "Paused". - # size = super().sizeHint() - # size.setWidth(86) - # return size - - -class AirWingConfigParkingTracker(QWidget): - allocation_changed = Signal() - - def __init__(self, game: Game) -> None: - super().__init__() - self.theater = game.theater - self.by_cp: dict[ControlPoint, set[Squadron]] = defaultdict(set) - for coalition in game.coalitions: - for squadron in coalition.air_wing.iter_squadrons(): - self.add_squadron(squadron) - - def add_squadron(self, squadron: Squadron) -> None: - self.by_cp[squadron.location].add(squadron) - self.signal_change() - - def remove_squadron(self, squadron: Squadron) -> None: - self.by_cp[squadron.location].remove(squadron) - self.signal_change() - - def relocate_squadron( - self, - squadron: Squadron, - prior_location: ControlPoint, - new_location: ControlPoint, - ) -> None: - self.by_cp[prior_location].remove(squadron) - self.by_cp[new_location].add(squadron) - squadron.relocate_to(new_location) - self.signal_change() - - def used_parking_at(self, control_point: ControlPoint) -> int: - return sum(s.max_size for s in self.by_cp[control_point]) - - def iter_overfull(self) -> Iterator[tuple[ControlPoint, int, list[Squadron]]]: - for control_point in self.theater.controlpoints: - used = self.used_parking_at(control_point) - if used > control_point.total_aircraft_parking: - yield control_point, used, list(self.by_cp[control_point]) - - def signal_change(self) -> None: - self.allocation_changed.emit() - - -class SquadronConfigurationBox(QGroupBox): - remove_squadron_signal = Signal(Squadron) - - def __init__( - self, - game: Game, - coalition: Coalition, - squadron: Squadron, - parking_tracker: AirWingConfigParkingTracker, - ) -> None: - super().__init__() - self.game = game - self.coalition = coalition - self.squadron = squadron - self.parking_tracker = parking_tracker - - columns = QHBoxLayout() - self.setLayout(columns) - - left_column = QVBoxLayout() - columns.addLayout(left_column) - - left_column.addWidget(QLabel("Name:")) - self.name_edit = QLineEdit(squadron.name) - self.name_edit.textChanged.connect(lambda x: self.reset_title()) - left_column.addWidget(self.name_edit) - - self.reset_title() - - nickname_edit_layout = QGridLayout() - left_column.addLayout(nickname_edit_layout) - - nickname_edit_layout.addWidget(QLabel("Nickname:"), 0, 0, 1, 2) - self.nickname_edit = QLineEdit(squadron.nickname) - nickname_edit_layout.addWidget(self.nickname_edit, 1, 0, Qt.AlignTop) - reroll_nickname_button = QToolButton() - reroll_nickname_button.setIcon(QIcon(ICONS["Reload"])) - reroll_nickname_button.setToolTip("Re-roll nickname") - reroll_nickname_button.clicked.connect(self.reroll_nickname) - nickname_edit_layout.addWidget(reroll_nickname_button, 1, 1, Qt.AlignTop) - - left_column.addWidget(QLabel("Livery:")) - self.livery_selector = LiverySelector(self.squadron) - left_column.addWidget(self.livery_selector) - - task_and_size_row = QHBoxLayout() - left_column.addLayout(task_and_size_row) - - size_column = QVBoxLayout() - left_column.addLayout(size_column) - size_column.addWidget(QLabel("Max size:")) - self.max_size_selector = SquadronSizeSpinner(self.squadron.max_size, self) - self.max_size_selector.valueChanged.connect(self.update_max_size) - size_column.addWidget(self.max_size_selector) - - task_column = QVBoxLayout() - left_column.addLayout(task_column) - task_column.addWidget(QLabel("Primary task:")) - self.primary_task_selector = PrimaryTaskSelector.for_squadron(self.squadron) - task_column.addWidget(self.primary_task_selector) - - left_column.addWidget(QLabel("Base:")) - self.base_selector = SquadronBaseSelector( - game.theater.control_points_for(squadron.player), - squadron.location, - squadron.aircraft, - ) - self.base_selector.currentIndexChanged.connect(self.relocate_squadron) - left_column.addWidget(self.base_selector) - - self.parking_label = QLabel() - self.update_parking_label() - self.parking_tracker.allocation_changed.connect(self.update_parking_label) - left_column.addWidget(self.parking_label) - - if not squadron.player and squadron.aircraft.flyable: - player_label = QLabel("Player slots not available for opfor") - elif not squadron.aircraft.flyable: - player_label = QLabel("Player slots not available for non-flyable aircraft") - else: - player_label = QLabel( - "Players (one per line, leave empty for an AI-only squadron):" - ) - left_column.addWidget(player_label) - - self.player_list = QTextEdit( - "
".join(p.name for p in self.claim_players_from_squadron()) - ) - self.player_list.setAcceptRichText(False) - self.player_list.setEnabled(squadron.player and squadron.aircraft.flyable) - left_column.addWidget(self.player_list) - - button_row = QHBoxLayout() - left_column.addLayout(button_row) - left_column.addStretch() - - delete_button = QPushButton("Remove Squadron") - delete_button.setMaximumWidth(140) - delete_button.clicked.connect(self.remove_from_squadron_config) - button_row.addWidget(delete_button) - - replace_button = QPushButton("Replace with preset") - replace_button.setMaximumWidth(140) - replace_button.clicked.connect(self.replace_with_preset) - button_row.addWidget(replace_button) - button_row.addStretch() - - right_column = QVBoxLayout() - self.mission_types = MissionTypeControls(squadron) - right_column.addLayout(self.mission_types) - right_column.addStretch() - columns.addLayout(right_column) - - def bind_data(self) -> None: - old_state = self.blockSignals(True) - try: - self.name_edit.setText(self.squadron.name) - self.nickname_edit.setText(self.squadron.nickname) - self.livery_selector.set_squadron(self.squadron) - self.primary_task_selector.setCurrentText(self.squadron.primary_task.value) - self.max_size_selector.setValue(self.squadron.max_size) - self.base_selector.setCurrentText(self.squadron.location.name) - self.player_list.setText( - "
".join(p.name for p in self.claim_players_from_squadron()) - ) - self.update_parking_label() - finally: - self.blockSignals(old_state) - - def update_parking_label(self) -> None: - self.parking_label.setText( - f"{self.parking_tracker.used_parking_at(self.squadron.location)}/" - f"{self.squadron.location.total_aircraft_parking}" - ) - - def update_max_size(self) -> None: - self.squadron.max_size = self.max_size_selector.value() - self.parking_tracker.signal_change() - - def relocate_squadron(self) -> None: - location = self.base_selector.currentData() - self.parking_tracker.relocate_squadron( - self.squadron, self.squadron.location, location - ) - - def remove_from_squadron_config(self) -> None: - self.remove_squadron_signal.emit(self.squadron) - - def pick_replacement_squadron(self) -> Squadron | None: - popup = PresetSquadronSelector( - self.squadron.aircraft, - self.coalition.air_wing.squadron_defs, - ) - if popup.exec_() != QDialog.Accepted: - return None - - selected_def = popup.squadron_def_selector.currentData() - - self.squadron.coalition.air_wing.unclaim_squadron_def(self.squadron) - squadron = Squadron.create_from( - selected_def, - self.squadron.primary_task, - self.squadron.max_size, - self.squadron.location, - self.coalition, - self.game, - ) - return squadron - - def claim_players_from_squadron(self) -> list[Pilot]: - if not self.squadron.player: - return [] - - players = [p for p in self.squadron.pilot_pool if p.player] - for player in players: - self.squadron.pilot_pool.remove(player) - return players - - def return_players_to_squadron(self) -> None: - if not self.squadron.player: - return - - player_names = self.player_list.toPlainText().splitlines() - # Prepend player pilots so they get set active first. - self.squadron.pilot_pool = [ - Pilot(n, player=True) for n in player_names - ] + self.squadron.pilot_pool - - def replace_with_preset(self) -> None: - new_squadron = self.pick_replacement_squadron() - if new_squadron is None: - # The user canceled the dialog. - return - self.return_players_to_squadron() - self.squadron = new_squadron - self.bind_data() - self.mission_types.replace_squadron(self.squadron) - self.parking_tracker.signal_change() - - def reset_title(self) -> None: - self.setTitle(f"{self.name_edit.text()} - {self.squadron.aircraft}") - - def reroll_nickname(self) -> None: - self.nickname_edit.setText( - self.squadron.coalition.air_wing.squadron_def_generator.random_nickname() - ) - - def apply(self) -> Squadron: - self.squadron.name = self.name_edit.text() - self.squadron.nickname = self.nickname_edit.text() - if (livery := self.livery_selector.selected_livery) is not None: - self.squadron.livery = livery.id - self.squadron.max_size = self.max_size_selector.value() - if (primary_task := self.primary_task_selector.selected_task) is not None: - self.squadron.primary_task = primary_task - else: - raise RuntimeError("Primary task cannot be none") - base = self.base_selector.currentData() - if base is None: - raise RuntimeError("Base cannot be none") - self.squadron.assign_to_base(base) - self.return_players_to_squadron() - - # Also update the auto assignable mission types - self.squadron.set_auto_assignable_mission_types( - set(self.mission_types.auto_assignable_mission_types) - ) - return self.squadron - - -class SquadronConfigurationLayout(QVBoxLayout): - config_changed = Signal(AircraftType) - - def __init__( - self, - game: Game, - coalition: Coalition, - squadrons: list[Squadron], - parking_tracker: AirWingConfigParkingTracker, - ) -> None: - super().__init__() - self.game = game - self.coalition = coalition - self.squadron_configs = [] - self.parking_tracker = parking_tracker - for squadron in squadrons: - self.add_squadron(squadron) - - def apply(self) -> list[Squadron]: - keep_squadrons = [] - for squadron_config in self.squadron_configs: - keep_squadrons.append(squadron_config.apply()) - return keep_squadrons - - def remove_squadron(self, squadron: Squadron) -> None: - self.parking_tracker.remove_squadron(squadron) - for squadron_config in self.squadron_configs: - if squadron_config.squadron == squadron: - squadron_config.deleteLater() - self.squadron_configs.remove(squadron_config) - squadron.coalition.air_wing.unclaim_squadron_def(squadron) - self.update() - self.config_changed.emit(squadron.aircraft) - return - - def add_squadron(self, squadron: Squadron) -> None: - squadron_config = SquadronConfigurationBox( - self.game, self.coalition, squadron, self.parking_tracker - ) - squadron_config.remove_squadron_signal.connect(self.remove_squadron) - self.squadron_configs.append(squadron_config) - self.addWidget(squadron_config) - self.parking_tracker.add_squadron(squadron) - - -class AircraftSquadronsPage(QWidget): - remove_squadron_page = Signal(AircraftType) - - def __init__( - self, - game: Game, - coalition: Coalition, - squadrons: list[Squadron], - parking_tracker: AirWingConfigParkingTracker, - ) -> None: - super().__init__() - layout = QVBoxLayout() - self.setLayout(layout) - - self.squadrons_config = SquadronConfigurationLayout( - game, coalition, squadrons, parking_tracker - ) - self.squadrons_config.config_changed.connect(self.on_squadron_config_changed) - - scrolling_widget = QWidget() - scrolling_widget.setLayout(self.squadrons_config) - - scrolling_area = QScrollArea() - scrolling_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scrolling_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scrolling_area.setWidgetResizable(True) - scrolling_area.setWidget(scrolling_widget) - - layout.addWidget(scrolling_area) - - def on_squadron_config_changed(self, aircraft_type: AircraftType): - if len(self.squadrons_config.squadron_configs) == 0: - self.remove_squadron_page.emit(aircraft_type) - - def add_squadron_to_page(self, squadron: Squadron): - self.squadrons_config.add_squadron(squadron) - - def apply(self) -> list[Squadron]: - return self.squadrons_config.apply() - - -class AircraftSquadronsPanel(QStackedLayout): - page_removed = Signal(AircraftType) - - def __init__( - self, - game: Game, - coalition: Coalition, - parking_tracker: AirWingConfigParkingTracker, - ) -> None: - super().__init__() - self.game = game - self.coalition = coalition - self.parking_tracker = parking_tracker - self.squadrons_pages: dict[AircraftType, AircraftSquadronsPage] = {} - for aircraft, squadrons in self.air_wing.squadrons.items(): - self.new_page_for_type(aircraft, squadrons) - - @property - def air_wing(self) -> AirWing: - return self.coalition.air_wing - - def remove_page_for_type(self, aircraft_type: AircraftType): - page = self.squadrons_pages[aircraft_type] - self.removeWidget(page) - page.deleteLater() - self.squadrons_pages.pop(aircraft_type) - self.page_removed.emit(aircraft_type) - self.update() - - def new_page_for_type( - self, aircraft_type: AircraftType, squadrons: list[Squadron] - ) -> None: - page = AircraftSquadronsPage( - self.game, self.coalition, squadrons, self.parking_tracker - ) - page.remove_squadron_page.connect(self.remove_page_for_type) - self.addWidget(page) - self.squadrons_pages[aircraft_type] = page - - def add_squadron_to_panel(self, squadron: Squadron): - # Find existing page or add new one - if squadron.aircraft in self.squadrons_pages: - page = self.squadrons_pages[squadron.aircraft] - page.add_squadron_to_page(squadron) - else: - self.new_page_for_type(squadron.aircraft, [squadron]) - - self.update() - - def apply(self) -> None: - self.air_wing.squadrons = {} - for aircraft, page in self.squadrons_pages.items(): - self.air_wing.squadrons[aircraft] = page.apply() - - def revert(self) -> None: - for _, page in self.squadrons_pages.items(): - self.removeWidget(page) - self.squadrons_pages: dict[AircraftType, AircraftSquadronsPage] = {} - for aircraft, squadrons in self.air_wing.squadrons.items(): - self.new_page_for_type(aircraft, squadrons) - self.update() - - -class AircraftTypeList(QListView): - page_index_changed = Signal(int) - - def __init__(self, air_wing: AirWing) -> None: - super().__init__() - self.air_wing = air_wing - self.setIconSize(QSize(91, 24)) - self.setMinimumWidth(300) - - self.item_model = QStandardItemModel(self) - self.setModel(self.item_model) - - self.selectionModel().setCurrentIndex( - self.item_model.index(0, 0), QItemSelectionModel.Select - ) - self.selectionModel().selectionChanged.connect(self.on_selection_changed) - for aircraft in air_wing.squadrons: - self.add_aircraft_type(aircraft) - - def remove_aircraft_type(self, aircraft: AircraftType): - for item in self.item_model.findItems(aircraft.display_name): - self.item_model.removeRow(item.row()) - self.page_index_changed.emit(self.selectionModel().currentIndex().row()) - - def add_aircraft_type(self, aircraft: AircraftType): - aircraft_item = QStandardItem(aircraft.display_name) - icon = self.icon_for(aircraft) - if icon is not None: - aircraft_item.setIcon(icon) - aircraft_item.setEditable(False) - aircraft_item.setSelectable(True) - self.item_model.appendRow(aircraft_item) - - def on_selection_changed( - self, selected: QItemSelection, _deselected: QItemSelection - ) -> None: - indexes = selected.indexes() - if len(indexes) > 1: - raise RuntimeError("Aircraft list should not allow multi-selection") - if not indexes: - return - self.page_index_changed.emit(indexes[0].row()) - - @staticmethod - def icon_for(aircraft: AircraftType) -> Optional[QIcon]: - name = aircraft.dcs_id - if name in AIRCRAFT_ICONS: - return QIcon(AIRCRAFT_ICONS[name]) - return None - - def revert(self) -> None: - self.item_model.clear() - for aircraft in self.air_wing.squadrons: - self.add_aircraft_type(aircraft) - self.update(self.selectionModel().currentIndex()) - - -def describe_overfull_airbases( - overfull: Iterable[tuple[ControlPoint, int, list[Squadron]]] -) -> str: - string_builder = [] - for ( - control_point, - used_parking, - squadrons, - ) in overfull: - capacity = control_point.total_aircraft_parking - base_description = f"{control_point.name} {used_parking}/{capacity}" - string_builder.append(f"

{base_description}

") - squadron_descriptions = [] - for squadron in squadrons: - squadron_details = ( - f"{squadron.aircraft} {squadron.name} {squadron.max_size} aircraft" - ) - squadron_descriptions.append(f"
  • {squadron_details}
  • ") - string_builder.append(f"
      {''.join(squadron_descriptions)}
    ") - - if not string_builder: - string_builder.append("All airbases are within parking limits.") - - return "".join(string_builder) - - -class OverfullAirbasesDisplay(QGroupBox): - def __init__( - self, - parking_tracker: AirWingConfigParkingTracker, - parent: QWidget | None = None, - ) -> None: - super().__init__("Overfull airbases", parent) - self.setMaximumHeight(200) - - self.parking_tracker = parking_tracker - self.parking_tracker.allocation_changed.connect(self.on_allocation_changed) - - layout = QVBoxLayout() - self.setLayout(layout) - - self.label = QLabel() - - scroll = QScrollArea() - scroll.setWidgetResizable(True) - scroll.setWidget(self.label) - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - layout.addWidget(scroll) - - self.on_allocation_changed() - - def on_allocation_changed(self) -> None: - self.label.setText( - describe_overfull_airbases(self.parking_tracker.iter_overfull()) - ) - - -class AirWingConfigurationTab(QWidget): - def __init__( - self, - coalition: Coalition, - game: Game, - parking_tracker: AirWingConfigParkingTracker, - ) -> None: - super().__init__() - - layout = QGridLayout() - self.setLayout(layout) - self.game = game - self.coalition = coalition - self.parking_tracker = parking_tracker - - self.type_list = AircraftTypeList(coalition.air_wing) - - layout.addWidget(self.type_list, 1, 1, 1, 2) - - add_button = QPushButton("Add Squadron") - add_button.clicked.connect(lambda state: self.add_squadron()) - layout.addWidget(add_button, 2, 1, 1, 1) - - self.squadrons_panel = AircraftSquadronsPanel( - game, coalition, self.parking_tracker - ) - self.squadrons_panel.page_removed.connect(self.type_list.remove_aircraft_type) - layout.addLayout(self.squadrons_panel, 1, 3, 2, 1) - - self.type_list.page_index_changed.connect(self.squadrons_panel.setCurrentIndex) - - def add_squadron(self) -> None: - selected_aircraft = None - if self.type_list.selectionModel().currentIndex().row() >= 0: - selected_aircraft = self.type_list.item_model.item( - self.type_list.selectionModel().currentIndex().row() - ).text() - - bases = list(self.game.theater.control_points_for(self.coalition.player)) - - # List of all Aircrafts possible to operate with the given bases - possible_aircrafts = [ - aircraft - for aircraft in self.coalition.faction.aircrafts - if any(base.can_operate(aircraft) for base in bases) - ] - - popup = SquadronConfigPopup( - selected_aircraft, - possible_aircrafts, - bases, - self.coalition.air_wing.squadron_defs, - ) - if popup.exec_() != QDialog.Accepted: - return - - selected_type = popup.aircraft_type_selector.currentData() - selected_base = popup.squadron_base_selector.currentData() - selected_task = popup.primary_task_selector.selected_task - selected_def = popup.squadron_def_selector.currentData() - - # Let user choose the preset or generate one - squadron_def = ( - selected_def - or self.coalition.air_wing.squadron_def_generator.generate_for_aircraft( - selected_type - ) - ) - - squadron = Squadron.create_from( - squadron_def, - selected_task, - DEFAULT_SQUADRON_SIZE, - selected_base, - self.coalition, - self.game, - ) - - # Add Squadron - if not self.type_list.item_model.findItems(selected_type.display_name): - self.type_list.add_aircraft_type(selected_type) - # TODO Select the newly added type - self.squadrons_panel.add_squadron_to_panel(squadron) - self.update() - - def apply(self) -> None: - self.squadrons_panel.apply() - - def revert(self) -> None: - self.type_list.revert() - self.squadrons_panel.revert() - self.update() - - -class AirWingConfigurationDialog(QDialog): - """Dialog window for air wing configuration.""" - - def __init__(self, game: Game, parent) -> None: - super().__init__(parent) - self.game = game - self.parking_tracker = AirWingConfigParkingTracker(game) - - self.setMinimumSize(1024, 768) - self.setWindowTitle(f"Air Wing Configuration") - # TODO: self.setWindowIcon() - - layout = QVBoxLayout() - self.setLayout(layout) - - doc_label = QLabel( - "Use this opportunity to customize the squadrons available to your " - "coalition. This is your only opportunity to make changes." - "

    " - "To accept your changes and continue, close this window." - ) - - layout.addWidget(doc_label) - - self.tab_widget = QTabWidget() - layout.addWidget(self.tab_widget) - - self.tabs = [] - for coalition in game.coalitions: - coalition_tab = AirWingConfigurationTab( - coalition, game, self.parking_tracker - ) - name = "Blue" if coalition.player else "Red" - self.tab_widget.addTab(coalition_tab, name) - self.tabs.append(coalition_tab) - - self.overfull_airbases_display = OverfullAirbasesDisplay( - self.parking_tracker, self - ) - layout.addWidget(self.overfull_airbases_display) - - buttons_layout = QHBoxLayout() - apply_button = QPushButton("Accept Changes && Start Campaign") - apply_button.setProperty("style", "btn-accept") - apply_button.clicked.connect(lambda state: self.accept()) - discard_button = QPushButton("Reset Changes") - discard_button.setProperty("style", "btn-danger") - discard_button.clicked.connect(lambda state: self.revert()) - buttons_layout.addWidget(discard_button) - buttons_layout.addWidget(apply_button) - layout.addLayout(buttons_layout) - - def revert(self) -> None: - for tab in self.tabs: - tab.revert() - - def can_continue(self) -> bool: - overfull = list(self.parking_tracker.iter_overfull()) - if not overfull: - return True - - description = ( - "

    The following airbases are over capacity:

    " - f"{describe_overfull_airbases(overfull)}" - ) - QMessageBox().critical( - self, - "Cannot continue with overfull bases", - description, - QMessageBox.Ok, - ) - return False - - def accept(self) -> None: - if not self.can_continue(): - return - for tab in self.tabs: - tab.apply() - super().accept() - - def reject(self) -> None: - result = QMessageBox.information( - None, - "Abort new game?", - "
    ".join( - textwrap.wrap( - "Are you sure you want to cancel air wing configuration and " - "return to the new game wizard? If you instead want to revert your " - "air wing changes and continue, use the revert and accept buttons " - "below.", - width=55, - ) - ), - QMessageBox.Yes, - QMessageBox.No, - ) - if result == QMessageBox.No: - return - super().reject() - - -class SquadronAircraftTypeSelector(QComboBox): - def __init__( - self, types: list[AircraftType], selected_aircraft: Optional[str] - ) -> None: - super().__init__() - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - - for type in sorted(types, key=lambda type: type.display_name): - self.addItem(type.display_name, type) - - if selected_aircraft: - self.setCurrentText(selected_aircraft) - - -class SquadronDefSelector(QComboBox): - def __init__( - self, - squadron_defs: dict[AircraftType, list[SquadronDef]], - aircraft: Optional[AircraftType], - allow_random: bool = True, - ) -> None: - super().__init__() - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.squadron_defs = squadron_defs - self.allow_random = allow_random - self.set_aircraft_type(aircraft) - - def set_aircraft_type(self, aircraft: Optional[AircraftType]): - self.clear() - if self.allow_random: - self.addItem("None (Random)", None) - if aircraft and aircraft in self.squadron_defs: - for squadron_def in sorted( - self.squadron_defs[aircraft], key=lambda squadron_def: squadron_def.name - ): - if not squadron_def.claimed: - squadron_name = squadron_def.name - if squadron_def.nickname: - squadron_name += " (" + squadron_def.nickname + ")" - self.addItem(squadron_name, squadron_def) - self.setCurrentIndex(0) - - -class SquadronConfigPopup(QDialog): - def __init__( - self, - selected_aircraft: Optional[str], - types: list[AircraftType], - bases: list[ControlPoint], - squadron_defs: dict[AircraftType, list[SquadronDef]], - ) -> None: - super().__init__() - - self.setWindowTitle(f"Add new Squadron") - - self.column = QVBoxLayout() - self.setLayout(self.column) - - self.column.addWidget(QLabel("Aircraft:")) - self.aircraft_type_selector = SquadronAircraftTypeSelector( - types, selected_aircraft - ) - self.aircraft_type_selector.currentIndexChanged.connect( - self.on_aircraft_selection - ) - self.column.addWidget(self.aircraft_type_selector) - - self.column.addWidget(QLabel("Primary task:")) - self.primary_task_selector = PrimaryTaskSelector( - self.aircraft_type_selector.currentData() - ) - self.column.addWidget(self.primary_task_selector) - - self.column.addWidget(QLabel("Base:")) - self.squadron_base_selector = SquadronBaseSelector( - bases, None, self.aircraft_type_selector.currentData() - ) - self.column.addWidget(self.squadron_base_selector) - - self.column.addWidget(QLabel("Preset:")) - self.squadron_def_selector = SquadronDefSelector( - squadron_defs, self.aircraft_type_selector.currentData() - ) - self.column.addWidget(self.squadron_def_selector) - - self.column.addStretch() - - self.button_layout = QHBoxLayout() - self.column.addLayout(self.button_layout) - - self.accept_button = QPushButton("Accept") - self.accept_button.clicked.connect(lambda state: self.accept()) - self.update_accept_button() - self.button_layout.addWidget(self.accept_button) - - self.cancel_button = QPushButton("Cancel") - self.cancel_button.clicked.connect(lambda state: self.reject()) - self.button_layout.addWidget(self.cancel_button) - - def update_accept_button(self) -> None: - enabled = ( - self.aircraft_type_selector.currentData() is not None - and self.squadron_base_selector.currentData() is not None - and self.primary_task_selector.selected_task is not None - ) - self.accept_button.setEnabled(enabled) - - def on_aircraft_selection(self) -> None: - self.squadron_base_selector.set_aircraft_type( - self.aircraft_type_selector.currentData() - ) - self.squadron_def_selector.set_aircraft_type( - self.aircraft_type_selector.currentData() - ) - self.primary_task_selector.set_aircraft( - self.aircraft_type_selector.currentData() - ) - self.update_accept_button() - self.update() - - -class PresetSquadronSelector(QDialog): - def __init__( - self, - aircraft: AircraftType, - squadron_defs: dict[AircraftType, list[SquadronDef]], - ) -> None: - super().__init__() - - self.setWindowTitle(f"Choose preset squadron") - - self.column = QVBoxLayout() - self.setLayout(self.column) - - self.column.addWidget(QLabel("Preset:")) - self.squadron_def_selector = SquadronDefSelector( - squadron_defs, aircraft, allow_random=False - ) - self.column.addWidget(self.squadron_def_selector) - - self.column.addStretch() - - self.button_layout = QHBoxLayout() - self.column.addLayout(self.button_layout) - - self.accept_button = QPushButton("Accept") - self.accept_button.clicked.connect(lambda state: self.accept()) - self.button_layout.addWidget(self.accept_button) - - self.cancel_button = QPushButton("Cancel") - self.cancel_button.clicked.connect(lambda state: self.reject()) - self.button_layout.addWidget(self.cancel_button) diff --git a/qt_ui/windows/AirWingDialog.py b/qt_ui/windows/AirWingDialog.py deleted file mode 100644 index c62f26f73..000000000 --- a/qt_ui/windows/AirWingDialog.py +++ /dev/null @@ -1,262 +0,0 @@ -from __future__ import annotations - -from dataclasses import dataclass -from typing import Iterator, Optional - -from PySide6.QtCore import QItemSelectionModel, QModelIndex, QSize -from PySide6.QtWidgets import ( - QAbstractItemView, - QCheckBox, - QDialog, - QHBoxLayout, - QListView, - QTabWidget, - QTableWidget, - QTableWidgetItem, - QVBoxLayout, - QWidget, -) - -from game.ato.flight import Flight -from game.squadrons import Squadron -from game.theater import ConflictTheater -from qt_ui.delegates import TwoColumnRowDelegate -from qt_ui.models import AirWingModel, AtoModel, GameModel, SquadronModel -from qt_ui.simcontroller import SimController -from qt_ui.windows.SquadronDialog import SquadronDialog - - -class SquadronDelegate(TwoColumnRowDelegate): - def __init__(self, air_wing_model: AirWingModel) -> None: - super().__init__(rows=2, columns=2, font_size=12) - self.air_wing_model = air_wing_model - - @staticmethod - def squadron(index: QModelIndex) -> Squadron: - return index.data(AirWingModel.SquadronRole) - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - squadron = self.squadron(index) - if (row, column) == (0, 0): - if squadron.nickname: - nickname = f' "{squadron.nickname}"' - else: - nickname = "" - return f"{squadron.name}{nickname}" - elif (row, column) == (0, 1): - return squadron.aircraft.display_name - elif (row, column) == (1, 0): - return squadron.location.name - elif (row, column) == (1, 1): - squadron = self.squadron(index) - active = len(squadron.active_pilots) - available = len(squadron.available_pilots) - on_leave = len(squadron.pilots_on_leave) - return f"{active} active, {available} unassigned, {on_leave} on leave" - return "" - - -class SquadronList(QListView): - """List view for displaying the air wing's squadrons.""" - - def __init__( - self, - ato_model: AtoModel, - air_wing_model: AirWingModel, - theater: ConflictTheater, - sim_controller: SimController, - ) -> None: - super().__init__() - self.ato_model = ato_model - self.air_wing_model = air_wing_model - self.theater = theater - self.sim_controller = sim_controller - self.dialog: Optional[SquadronDialog] = None - - self.setIconSize(QSize(91, 24)) - self.setItemDelegate(SquadronDelegate(self.air_wing_model)) - self.setModel(self.air_wing_model) - self.selectionModel().setCurrentIndex( - self.air_wing_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select - ) - - # self.setIconSize(QSize(91, 24)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - self.doubleClicked.connect(self.on_double_click) - - def on_double_click(self, index: QModelIndex) -> None: - if not index.isValid(): - return - self.dialog = SquadronDialog( - self.ato_model, - SquadronModel(self.air_wing_model.squadron_at_index(index)), - self.theater, - self.sim_controller, - self, - ) - self.dialog.show() - - -@dataclass(frozen=True) -class AircraftInventoryData: - location: str - unit_type: str - task: str - target: str - pilot: str - player: str - - @classmethod - def headers(cls) -> list[str]: - return ["Base", "Type", "Flight Type", "Target", "Pilot", "Player"] - - @property - def columns(self) -> Iterator[str]: - yield self.location - yield self.unit_type - yield self.task - yield self.target - yield self.pilot - yield self.player - - @classmethod - def from_flight(cls, flight: Flight) -> Iterator[AircraftInventoryData]: - num_units = flight.count - flight_type = flight.flight_type.value - target = flight.package.target.name - for idx in range(0, num_units): - pilot = flight.roster.pilot_at(idx) - if pilot is None: - pilot_name = "Unassigned" - player = "" - else: - pilot_name = pilot.name - player = "Player" if pilot.player else "AI" - yield AircraftInventoryData( - flight.departure.name, - flight.unit_type.display_name, - flight_type, - target, - pilot_name, - player, - ) - - @classmethod - def each_untasked_from_squadron( - cls, squadron: Squadron - ) -> Iterator[AircraftInventoryData]: - for _ in range(0, squadron.untasked_aircraft): - yield AircraftInventoryData( - squadron.name, - squadron.aircraft.display_name, - "Idle", - "N/A", - "N/A", - "N/A", - ) - - -class AirInventoryView(QWidget): - def __init__(self, game_model: GameModel) -> None: - super().__init__() - self.game_model = game_model - - self.only_unallocated = False - self.enemy_info = False - - layout = QVBoxLayout() - self.setLayout(layout) - - checkbox_row = QHBoxLayout() - layout.addLayout(checkbox_row) - - self.only_unallocated_cb = QCheckBox("Unallocated only") - self.only_unallocated_cb.toggled.connect(self.set_only_unallocated) - checkbox_row.addWidget(self.only_unallocated_cb) - - self.enemy_info_cb = QCheckBox("Show enemy info") - self.enemy_info_cb.toggled.connect(self.set_enemy_info) - checkbox_row.addWidget(self.enemy_info_cb) - - checkbox_row.addStretch() - - self.table = QTableWidget() - layout.addWidget(self.table) - - self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) - self.table.verticalHeader().setVisible(False) - self.set_only_unallocated(False) - - def set_only_unallocated(self, value: bool) -> None: - self.only_unallocated = value - self.update_table() - - def set_enemy_info(self, value: bool) -> None: - self.enemy_info = value - self.update_table() - - def update_table(self) -> None: - self.table.setSortingEnabled(False) - self.table.clear() - - inventory_rows = list(self.get_data()) - self.table.setRowCount(len(inventory_rows)) - headers = AircraftInventoryData.headers() - self.table.setColumnCount(len(headers)) - self.table.setHorizontalHeaderLabels(headers) - - for row, data in enumerate(inventory_rows): - for column, value in enumerate(data.columns): - self.table.setItem(row, column, QTableWidgetItem(value)) - - self.table.resizeColumnsToContents() - self.table.setSortingEnabled(True) - - def iter_allocated_aircraft(self) -> Iterator[AircraftInventoryData]: - coalition = self.game_model.game.coalition_for(not self.enemy_info) - for package in coalition.ato.packages: - for flight in package.flights: - yield from AircraftInventoryData.from_flight(flight) - - def iter_unallocated_aircraft(self) -> Iterator[AircraftInventoryData]: - coalition = self.game_model.game.coalition_for(not self.enemy_info) - for squadron in coalition.air_wing.iter_squadrons(): - yield from AircraftInventoryData.each_untasked_from_squadron(squadron) - - def get_data(self) -> Iterator[AircraftInventoryData]: - yield from self.iter_unallocated_aircraft() - if not self.only_unallocated: - yield from self.iter_allocated_aircraft() - - -class AirWingTabs(QTabWidget): - def __init__(self, game_model: GameModel) -> None: - super().__init__() - - self.addTab( - SquadronList( - game_model.ato_model, - game_model.blue_air_wing_model, - game_model.game.theater, - game_model.sim_controller, - ), - "Squadrons", - ) - self.addTab(AirInventoryView(game_model), "Inventory") - - -class AirWingDialog(QDialog): - """Dialog window showing the player's air wing.""" - - def __init__(self, game_model: GameModel, parent) -> None: - super().__init__(parent) - self.air_wing_model = game_model.blue_air_wing_model - - self.setMinimumSize(1000, 440) - self.setWindowTitle(f"Air Wing") - # TODO: self.setWindowIcon() - - layout = QVBoxLayout() - self.setLayout(layout) - - layout.addWidget(AirWingTabs(game_model)) diff --git a/qt_ui/windows/BugReportDialog.py b/qt_ui/windows/BugReportDialog.py deleted file mode 100644 index 6fa5af545..000000000 --- a/qt_ui/windows/BugReportDialog.py +++ /dev/null @@ -1,58 +0,0 @@ -import webbrowser - -from PySide6.QtCore import Qt -from PySide6.QtGui import QGuiApplication -from PySide6.QtWidgets import QDialog, QLabel, QPushButton, QVBoxLayout, QWidget - -from game.version import BUILD_NUMBER, GIT_SHA, VERSION_NUMBER - - -class BugReportDialog(QDialog): - def __init__(self, parent: QWidget) -> None: - super().__init__(parent) - self.setWindowTitle("Report an issue") - self.setModal(True) - self.setMaximumWidth(600) - - layout = QVBoxLayout() - self.setLayout(layout) - - components = [f"DCS Liberation {VERSION_NUMBER}"] - if BUILD_NUMBER is not None: - components.append(f"Build {BUILD_NUMBER}") - if GIT_SHA is not None: - components.append(f"Git revision {GIT_SHA}") - - self.report_data = "\n".join(components) - - label = QLabel( - "Use the button below to file a bug. The version information will be " - "automatically copied to your clipboard. Paste that information into the " - "box in the bug template that asks for the version.
    " - "
    " - "Look for duplicate bugs before filing.
    " - "
    " - "If the template asks for a save game, it is required. No matter " - "how easily reproducible the bug may appear, it rarely is. If it were " - "obvious you wouldn't be the first to find it.
    " - "
    " - f"{'
    '.join(components)}
    " - ) - label.setTextInteractionFlags( - Qt.TextSelectableByMouse - | Qt.LinksAccessibleByMouse - | Qt.LinksAccessibleByKeyboard - ) - label.setWordWrap(True) - label.setOpenExternalLinks(True) - layout.addWidget(label) - - copy_button = QPushButton("Copy details to clipboard and go to bug page") - copy_button.clicked.connect(self.on_file_bug) - layout.addWidget(copy_button) - - def on_file_bug(self) -> None: - QGuiApplication.clipboard().setText(self.report_data) - webbrowser.open_new_tab( - "https://github.com/dcs-liberation/dcs_liberation/issues/new/choose" - ) diff --git a/qt_ui/windows/GameUpdateSignal.py b/qt_ui/windows/GameUpdateSignal.py deleted file mode 100644 index b3fe12621..000000000 --- a/qt_ui/windows/GameUpdateSignal.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from PySide6.QtCore import QObject, Signal - -from game import Game -from game.debriefing import Debriefing - - -class GameUpdateSignal(QObject): - instance = None - gameupdated = Signal(Game) - budgetupdated = Signal(Game) - debriefingReceived = Signal(Debriefing) - - game_loaded = Signal(Game) - game_generated = Signal(Game) - - def __init__(self): - super(GameUpdateSignal, self).__init__() - GameUpdateSignal.instance = self - - self.game_loaded.connect(self.updateGame) - - def updateGame(self, game: Optional[Game]): - # noinspection PyUnresolvedReferences - self.gameupdated.emit(game) - - def updateBudget(self, game: Game): - # noinspection PyUnresolvedReferences - self.budgetupdated.emit(game) - - def sendDebriefing(self, debriefing: Debriefing) -> None: - # noinspection PyUnresolvedReferences - self.debriefingReceived.emit(debriefing) - - @staticmethod - def get_instance() -> GameUpdateSignal: - return GameUpdateSignal.instance diff --git a/qt_ui/windows/PendingTransfersDialog.py b/qt_ui/windows/PendingTransfersDialog.py deleted file mode 100644 index 876d026a4..000000000 --- a/qt_ui/windows/PendingTransfersDialog.py +++ /dev/null @@ -1,125 +0,0 @@ -from PySide6.QtCore import ( - QItemSelection, - QItemSelectionModel, - QModelIndex, - Qt, -) -from PySide6.QtGui import QAction, QContextMenuEvent -from PySide6.QtWidgets import ( - QAbstractItemView, - QDialog, - QHBoxLayout, - QListView, - QMenu, - QPushButton, - QVBoxLayout, -) - -from game.transfers import TransferOrder -from qt_ui.delegates import TwoColumnRowDelegate -from qt_ui.models import GameModel, TransferModel - - -class TransferDelegate(TwoColumnRowDelegate): - def __init__(self, transfer_model: TransferModel) -> None: - super().__init__(rows=2, columns=1, font_size=12) - self.transfer_model = transfer_model - - @staticmethod - def transfer(index: QModelIndex) -> TransferOrder: - return index.data(TransferModel.TransferRole) - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - if row == 0: - return self.transfer_model.data(index, Qt.DisplayRole) - elif row == 1: - return self.transfer(index).description - return "" - - -class PendingTransfersList(QListView): - """List view for displaying the pending unit transfers.""" - - def __init__(self, transfer_model: TransferModel) -> None: - super().__init__() - self.transfer_model = transfer_model - - self.setItemDelegate(TransferDelegate(self.transfer_model)) - self.setModel(self.transfer_model) - self.selectionModel().setCurrentIndex( - self.transfer_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select - ) - - # self.setIconSize(QSize(91, 24)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - - def contextMenuEvent(self, event: QContextMenuEvent) -> None: - index = self.indexAt(event.pos()) - if not index.isValid(): - return - if not self.transfer_model.transfer_at_index(index).player: - return - - menu = QMenu("Menu") - - delete_action = QAction("Cancel") - delete_action.triggered.connect(lambda: self.cancel_transfer(index)) - menu.addAction(delete_action) - - menu.exec_(event.globalPos()) - - def cancel_transfer(self, index: QModelIndex) -> None: - """Cancels the given transfer order.""" - self.transfer_model.cancel_transfer_at_index(index) - - -class PendingTransfersDialog(QDialog): - """Dialog window showing all scheduled transfers for the player.""" - - def __init__(self, game_model: GameModel, parent=None) -> None: - super().__init__(parent) - self.transfer_model = game_model.transfer_model - - self.setMinimumSize(1000, 440) - self.setWindowTitle(f"Pending Transfers") - # TODO: self.setWindowIcon() - - layout = QVBoxLayout() - self.setLayout(layout) - - self.transfer_list = PendingTransfersList(self.transfer_model) - self.transfer_list.selectionModel().selectionChanged.connect( - self.on_selection_changed - ) - layout.addWidget(self.transfer_list) - - button_layout = QHBoxLayout() - layout.addLayout(button_layout) - - button_layout.addStretch() - - self.cancel_button = QPushButton("Cancel Transfer") - self.cancel_button.setProperty("style", "btn-danger") - self.cancel_button.clicked.connect(self.on_cancel_transfer) - self.cancel_button.setEnabled( - self.can_cancel(self.transfer_list.currentIndex()) - ) - button_layout.addWidget(self.cancel_button) - - def on_cancel_transfer(self) -> None: - """Cancels the selected transfer order.""" - self.transfer_model.cancel_transfer_at_index(self.transfer_list.currentIndex()) - - def can_cancel(self, index: QModelIndex) -> bool: - if not index.isValid(): - return False - return self.transfer_model.transfer_at_index(index).player - - def on_selection_changed( - self, selected: QItemSelection, _deselected: QItemSelection - ) -> None: - """Updates the state of the delete button.""" - if selected.empty(): - self.cancel_button.setEnabled(False) - return - self.cancel_button.setEnabled(self.can_cancel(selected.indexes()[0])) diff --git a/qt_ui/windows/QDebriefingWindow.py b/qt_ui/windows/QDebriefingWindow.py deleted file mode 100644 index 5124102a2..000000000 --- a/qt_ui/windows/QDebriefingWindow.py +++ /dev/null @@ -1,102 +0,0 @@ -import logging -from typing import Callable, Dict, TypeVar - -from PySide6.QtGui import QIcon, QPixmap -from PySide6.QtWidgets import ( - QDialog, - QGridLayout, - QGroupBox, - QLabel, - QPushButton, - QScrollArea, - QVBoxLayout, - QWidget, -) - -from game.debriefing import Debriefing - -T = TypeVar("T") - - -class LossGrid(QGridLayout): - def __init__(self, debriefing: Debriefing, player: bool) -> None: - super().__init__() - - self.add_loss_rows( - debriefing.air_losses.by_type(player), lambda u: u.display_name - ) - self.add_loss_rows( - debriefing.front_line_losses_by_type(player), lambda u: str(u) - ) - self.add_loss_rows( - debriefing.convoy_losses_by_type(player), lambda u: f"{u} from convoy" - ) - self.add_loss_rows( - debriefing.cargo_ship_losses_by_type(player), - lambda u: f"{u} from cargo ship", - ) - self.add_loss_rows( - debriefing.airlift_losses_by_type(player), lambda u: f"{u} from airlift" - ) - self.add_loss_rows(debriefing.ground_object_losses_by_type(player), lambda u: u) - self.add_loss_rows(debriefing.scenery_losses_by_type(player), lambda u: u) - - # TODO: Display dead ground object units and runways. - - def add_loss_rows(self, losses: Dict[T, int], make_name: Callable[[T], str]): - for unit_type, count in losses.items(): - row = self.rowCount() - try: - name = make_name(unit_type) - except AttributeError: - logging.exception(f"Could not make unit name for {unit_type}") - name = unit_type.id - self.addWidget(QLabel(name), row, 0) - self.addWidget(QLabel(str(count)), row, 1) - - -class ScrollingCasualtyReportContainer(QGroupBox): - def __init__(self, debriefing: Debriefing, player: bool) -> None: - country = debriefing.player_country if player else debriefing.enemy_country - super().__init__(f"{country}'s lost units:") - scroll_content = QWidget() - scroll_content.setLayout(LossGrid(debriefing, player)) - scroll_area = QScrollArea() - scroll_area.setWidget(scroll_content) - layout = QVBoxLayout() - layout.addWidget(scroll_area) - self.setLayout(layout) - - -class QDebriefingWindow(QDialog): - def __init__(self, debriefing: Debriefing): - super(QDebriefingWindow, self).__init__() - self.debriefing = debriefing - - self.setModal(True) - self.setWindowTitle("Debriefing") - self.setMinimumSize(300, 200) - self.setWindowIcon(QIcon("./resources/icon.png")) - - layout = QVBoxLayout() - self.setLayout(layout) - - header = QLabel(self) - header.setGeometry(0, 0, 655, 106) - pixmap = QPixmap("./resources/ui/debriefing.png") - header.setPixmap(pixmap) - layout.addWidget(header) - layout.addStretch() - - title = QLabel("Casualty report") - layout.addWidget(title) - - player_lost_units = ScrollingCasualtyReportContainer(debriefing, player=True) - layout.addWidget(player_lost_units) - - enemy_lost_units = ScrollingCasualtyReportContainer(debriefing, player=False) - layout.addWidget(enemy_lost_units) - - okay = QPushButton("Okay") - okay.clicked.connect(self.close) - layout.addWidget(okay) diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py deleted file mode 100644 index 3392dfe52..000000000 --- a/qt_ui/windows/QLiberationWindow.py +++ /dev/null @@ -1,612 +0,0 @@ -import logging -import traceback -import webbrowser -from pathlib import Path -from typing import Optional - -from PySide6.QtCore import QSettings, Qt, Signal -from PySide6.QtGui import QAction, QActionGroup, QCloseEvent, QGuiApplication, QIcon -from PySide6.QtWidgets import ( - QApplication, - QFileDialog, - QMainWindow, - QMessageBox, - QSplitter, - QVBoxLayout, - QWidget, -) - -import qt_ui.uiconstants as CONST -from game import Game, VERSION -from game.debriefing import Debriefing -from game.layout import LAYOUTS -from game.persistence import SaveManager -from game.server import EventStream, GameContext -from game.server.dependencies import QtCallbacks, QtContext -from game.theater import ControlPoint, MissionTarget, TheaterGroundObject -from game.turnstate import TurnState -from qt_ui import liberation_install -from qt_ui.dialogs import Dialog -from qt_ui.logging_handler import HookableInMemoryHandler -from qt_ui.models import GameModel -from qt_ui.simcontroller import SimController -from qt_ui.uiflags import UiFlags -from qt_ui.uncaughtexceptionhandler import UncaughtExceptionHandler -from qt_ui.widgets.QTopPanel import QTopPanel -from qt_ui.widgets.ato import QAirTaskingOrderPanel -from qt_ui.widgets.map.QLiberationMap import QLiberationMap -from qt_ui.windows.AirWingDialog import AirWingDialog -from qt_ui.windows.BugReportDialog import BugReportDialog -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.PendingTransfersDialog import PendingTransfersDialog -from qt_ui.windows.QDebriefingWindow import QDebriefingWindow -from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2 -from qt_ui.windows.gameoverdialog import GameOverDialog -from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu -from qt_ui.windows.infos.QInfoPanel import QInfoPanel -from qt_ui.windows.logs.QLogsWindow import QLogsWindow -from qt_ui.windows.newgame.QNewGameWizard import NewGameWizard -from qt_ui.windows.notes.QNotesWindow import QNotesWindow -from qt_ui.windows.preferences.QLiberationPreferencesWindow import ( - QLiberationPreferencesWindow, -) -from qt_ui.windows.settings.QSettingsWindow import QSettingsWindow -from qt_ui.windows.stats.QStatsWindow import QStatsWindow - - -class QLiberationWindow(QMainWindow): - new_package_signal = Signal(MissionTarget) - tgo_info_signal = Signal(TheaterGroundObject) - control_point_info_signal = Signal(ControlPoint) - - def __init__(self, game: Game | None, ui_flags: UiFlags) -> None: - super().__init__() - - self._uncaught_exception_handler = UncaughtExceptionHandler(self) - - self.game = game - self.sim_controller = SimController(self.game) - self.sim_controller.sim_update.connect(EventStream.put_nowait) - self.game_model = GameModel(game, self.sim_controller) - GameContext.set_model(self.game_model) - self.new_package_signal.connect( - lambda target: Dialog.open_new_package_dialog(target, self) - ) - self.tgo_info_signal.connect(self.open_tgo_info_dialog) - self.control_point_info_signal.connect(self.open_control_point_info_dialog) - QtContext.set_callbacks( - QtCallbacks( - lambda target: self.new_package_signal.emit(target), - lambda tgo: self.tgo_info_signal.emit(tgo), - lambda cp: self.control_point_info_signal.emit(cp), - ) - ) - Dialog.set_game(self.game_model) - self.ato_panel = QAirTaskingOrderPanel(self.game_model) - self.info_panel = QInfoPanel(self.game) - self.liberation_map = QLiberationMap( - self.game_model, ui_flags.dev_ui_webserver, self - ) - - self.setGeometry(300, 100, 270, 100) - self.updateWindowTitle() - self.setWindowIcon(QIcon("./resources/icon.png")) - self.statusBar().showMessage("Ready") - - self.initUi(ui_flags) - self.initActions() - self.initToolbar() - self.initMenuBar() - self.connectSignals() - - # Default to maximized on the main display if we don't have any persistent - # configuration. - screen = QGuiApplication.primaryScreen().availableSize() - self.setGeometry(0, 0, screen.width(), screen.height()) - self.setWindowState(Qt.WindowMaximized) - - # But override it with the saved configuration if it exists. - self._restore_window_geometry() - - if self.game is None: - last_save_file = liberation_install.get_last_save_file() - if last_save_file: - try: - logging.info("Loading last saved game : " + str(last_save_file)) - game = SaveManager.load_player_save(last_save_file) - self.onGameGenerated(game) - self.updateWindowTitle(last_save_file if game else None) - except: - logging.exception("Error loading latest save game") - else: - logging.info("No existing save game") - else: - self.onGameGenerated(self.game) - - def initUi(self, ui_flags: UiFlags) -> None: - hbox = QSplitter(Qt.Horizontal) - vbox = QSplitter(Qt.Vertical) - hbox.addWidget(self.ato_panel) - hbox.addWidget(vbox) - vbox.addWidget(self.liberation_map) - vbox.addWidget(self.info_panel) - - # Will make the ATO sidebar as small as necessary to fit the content. In - # practice this means it is sized by the hints in the panel. - hbox.setSizes([1, 10000000]) - vbox.setSizes([600, 100]) - - vbox = QVBoxLayout() - vbox.setContentsMargins(0, 0, 0, 0) - vbox.addWidget( - QTopPanel( - self.game_model, - self.sim_controller, - ui_flags, - self.reset_to_pre_sim_checkpoint, - ) - ) - vbox.addWidget(hbox) - - central_widget = QWidget() - central_widget.setLayout(vbox) - self.setCentralWidget(central_widget) - - def connectSignals(self): - GameUpdateSignal.get_instance().gameupdated.connect(self.setGame) - GameUpdateSignal.get_instance().debriefingReceived.connect(self.onDebriefing) - GameUpdateSignal.get_instance().game_generated.connect(self.onGameGenerated) - - def initActions(self): - self.newGameAction = QAction("&New Game", self) - self.newGameAction.setIcon(QIcon(CONST.ICONS["New"])) - self.newGameAction.triggered.connect(self.newGame) - self.newGameAction.setShortcut("CTRL+N") - - self.openAction = QAction("&Open", self) - self.openAction.setIcon(QIcon(CONST.ICONS["Open"])) - self.openAction.triggered.connect(self.openFile) - self.openAction.setShortcut("CTRL+O") - - self.saveGameAction = QAction("&Save", self) - self.saveGameAction.setIcon(QIcon(CONST.ICONS["Save"])) - self.saveGameAction.triggered.connect(self.saveGame) - self.saveGameAction.setShortcut("CTRL+S") - - self.saveAsAction = QAction("Save &As", self) - self.saveAsAction.setIcon(QIcon(CONST.ICONS["Save"])) - self.saveAsAction.triggered.connect(self.saveGameAs) - self.saveAsAction.setShortcut("CTRL+A") - - self.showAboutDialogAction = QAction("&About DCS Liberation", self) - self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about")) - self.showAboutDialogAction.triggered.connect(self.showAboutDialog) - - self.showLiberationPrefDialogAction = QAction("&Preferences", self) - self.showLiberationPrefDialogAction.setIcon(QIcon.fromTheme("help-about")) - self.showLiberationPrefDialogAction.triggered.connect(self.showLiberationDialog) - - self.openDiscordAction = QAction("&Discord Server", self) - self.openDiscordAction.setIcon(CONST.ICONS["Discord"]) - self.openDiscordAction.triggered.connect( - lambda: webbrowser.open_new_tab( - "https://" + "discord.gg" + "/" + "bKrt" + "rkJ" - ) - ) - - self.openGithubAction = QAction("&Github Repo", self) - self.openGithubAction.setIcon(CONST.ICONS["Github"]) - self.openGithubAction.triggered.connect( - lambda: webbrowser.open_new_tab( - "https://github.com/dcs-liberation/dcs_liberation" - ) - ) - - self.ukraineAction = QAction("&Ukraine", self) - self.ukraineAction.setIcon(CONST.ICONS["Ukraine"]) - self.ukraineAction.triggered.connect( - lambda: webbrowser.open_new_tab("https://shdwp.github.io/ukraine/") - ) - - self.bug_report_action = QAction("Report an &issue", self) - self.bug_report_action.setIcon(CONST.ICONS["Bug"]) - self.bug_report_action.triggered.connect(self.show_bug_report_dialog) - - self.openLogsAction = QAction("Show &logs", self) - self.openLogsAction.triggered.connect(self.showLogsDialog) - - self.openSettingsAction = QAction("Settings", self) - self.openSettingsAction.setIcon(CONST.ICONS["Settings"]) - self.openSettingsAction.triggered.connect(self.showSettingsDialog) - - self.openStatsAction = QAction("Stats", self) - self.openStatsAction.setIcon(CONST.ICONS["Statistics"]) - self.openStatsAction.triggered.connect(self.showStatsDialog) - - self.openNotesAction = QAction("Notes", self) - self.openNotesAction.setIcon(CONST.ICONS["Notes"]) - self.openNotesAction.triggered.connect(self.showNotesDialog) - - self.openAirWingAction = QAction("Air Wing", self) - self.openAirWingAction.triggered.connect(self.showAirWingDialog) - - self.openTransfersAction = QAction("Transfers", self) - self.openTransfersAction.triggered.connect(self.showTransfersDialog) - - self.importTemplatesAction = QAction("Import Layouts", self) - self.importTemplatesAction.triggered.connect(self.import_templates) - - self.enable_game_actions(False) - - def enable_game_actions(self, enabled: bool): - self.openSettingsAction.setVisible(enabled) - self.openStatsAction.setVisible(enabled) - self.openNotesAction.setVisible(enabled) - - # Also Disable SaveAction to prevent Keyboard Shortcut - self.saveGameAction.setEnabled(enabled) - self.saveGameAction.setVisible(enabled) - self.saveAsAction.setEnabled(enabled) - self.saveAsAction.setVisible(enabled) - - def initToolbar(self): - self.tool_bar = self.addToolBar("File") - self.tool_bar.addAction(self.newGameAction) - self.tool_bar.addAction(self.openAction) - self.tool_bar.addAction(self.saveGameAction) - - self.links_bar = self.addToolBar("Links") - self.links_bar.addAction(self.openDiscordAction) - self.links_bar.addAction(self.openGithubAction) - self.links_bar.addAction(self.bug_report_action) - self.links_bar.addAction(self.ukraineAction) - - self.actions_bar = self.addToolBar("Actions") - self.actions_bar.addAction(self.openSettingsAction) - self.actions_bar.addAction(self.openStatsAction) - self.actions_bar.addAction(self.openNotesAction) - self.actions_bar.addAction(self.openAirWingAction) - self.actions_bar.addAction(self.openTransfersAction) - - def initMenuBar(self): - self.menu = self.menuBar() - - file_menu = self.menu.addMenu("&File") - file_menu.addAction(self.newGameAction) - file_menu.addAction(self.openAction) - file_menu.addSeparator() - file_menu.addAction(self.saveGameAction) - file_menu.addAction(self.saveAsAction) - file_menu.addSeparator() - file_menu.addAction(self.showLiberationPrefDialogAction) - file_menu.addSeparator() - file_menu.addAction("E&xit", self.close) - - tools_menu = self.menu.addMenu("&Developer tools") - tools_menu.addAction(self.importTemplatesAction) - - help_menu = self.menu.addMenu("&Help") - help_menu.addAction(self.openDiscordAction) - help_menu.addAction(self.openGithubAction) - help_menu.addAction(self.ukraineAction) - help_menu.addAction( - "&Releases", - lambda: webbrowser.open_new_tab( - "https://github.com/dcs-liberation/dcs_liberation/releases" - ), - ) - help_menu.addAction( - "&Online Manual", - lambda: webbrowser.open_new_tab( - "https://github.com/dcs-liberation/dcs_liberation/wiki" - ), - ) - help_menu.addAction( - "&ED Forum Thread", - lambda: webbrowser.open_new_tab( - "https://forums.eagle.ru/showthread.php?t=214834" - ), - ) - help_menu.addAction(self.bug_report_action) - help_menu.addAction(self.openLogsAction) - - help_menu.addSeparator() - help_menu.addAction(self.showAboutDialogAction) - - @staticmethod - def make_display_rule_action( - display_rule, group: Optional[QActionGroup] = None - ) -> QAction: - def make_check_closure(): - def closure(): - display_rule.value = action.isChecked() - - return closure - - action = QAction(f"&{display_rule.menu_text}", group) - - if display_rule.menu_text in CONST.ICONS.keys(): - action.setIcon(CONST.ICONS[display_rule.menu_text]) - - action.setCheckable(True) - action.setChecked(display_rule.value) - action.toggled.connect(make_check_closure()) - return action - - def newGame(self): - wizard = NewGameWizard(self) - wizard.show() - - def openFile(self): - if ( - self.game is not None - and self.game.save_manager.player_save_location is not None - ): - save_dir = str(self.game.save_manager.player_save_location) - else: - save_dir = str(SaveManager.default_save_directory()) - file = QFileDialog.getOpenFileName( - self, - "Select game file to open", - dir=save_dir, - filter="*.liberation.zip", - ) - if file is not None and file[0] != "": - try: - game = SaveManager.load_player_save(Path(file[0])) - GameUpdateSignal.get_instance().game_loaded.emit(game) - - self.updateWindowTitle(Path(file[0])) - except Exception: - logging.exception("Error loading save game %s", file[0]) - - def reset_to_pre_sim_checkpoint(self) -> None: - """Loads the game that was saved before pressing the take-off button. - - A checkpoint will be saved when the player presses take-off to save their state - before the mission simulation begins. If the mission is aborted, we usually want - to reset to the pre-simulation state to allow players to effectively "rewind", - since they probably aborted so that they could make changes. Implementing rewind - for real is impractical, but checkpoints are easy. - """ - if self.game is None: - raise RuntimeError( - "Cannot reset to pre-sim checkpoint when no game is loaded" - ) - GameUpdateSignal.get_instance().game_loaded.emit( - self.game.save_manager.load_pre_sim_checkpoint() - ) - - def saveGame(self): - logging.info("Saving game") - - if self.game.save_manager.player_save_location is not None: - self.game.save_manager.save_player() - else: - self.saveGameAs() - - def saveGameAs(self): - if ( - self.game is not None - and self.game.save_manager.player_save_location is not None - ): - save_dir = str(self.game.save_manager.player_save_location) - else: - save_dir = str(SaveManager.default_save_directory()) - file = QFileDialog.getSaveFileName( - self, - "Save As", - dir=save_dir, - filter="*.liberation.zip", - ) - if file is not None and file[0]: - self.game.save_manager.save_player(override_destination=Path(file[0])) - self.updateWindowTitle(Path(file[0])) - - def updateWindowTitle(self, save_path: Path | None = None) -> None: - """ - to DCS Liberation - vX.X.X - file_name - """ - window_title = f"DCS Liberation - v{VERSION}" - if save_path: # appending the file name to title as it is updated - file_name = save_path.name.split(".liberation.zip")[0] - window_title = f"{window_title} - {file_name}" - self.setWindowTitle(window_title) - - def onGameGenerated(self, game: Game): - self.updateWindowTitle() - logging.info("On Game generated") - self.game = game - GameUpdateSignal.get_instance().game_loaded.emit(self.game) - - def setGame(self, game: Optional[Game]): - try: - self.game = game - if self.info_panel is not None: - self.info_panel.setGame(game) - self.sim_controller.set_game(game) - self.game_model.set(self.game) - except AttributeError: - logging.exception("Incompatible save game") - QMessageBox.critical( - self, - "Could not load save game", - "The save game you have loaded is incompatible with this " - "version of DCS Liberation.\n" - "\n" - f"{traceback.format_exc()}", - QMessageBox.Ok, - ) - GameUpdateSignal.get_instance().updateGame(None) - finally: - self.enable_game_actions(self.game is not None) - - def showAboutDialog(self): - contributors = [ - "shdwp", - "Khopa", - "ColonelPanic", - "RndName", - "Roach", - "Malakhit", - "Wrycu", - "calvinmorrow", - "JohanAberg", - "Deus", - "SiKruger", - "Mustang-25", - "bgreman", - "magwo", - "SnappyComebacks", - "kavinsky", - "Schneefl0cke", - "pbzweihander", - "Raskil", - "nosv1", - "jake-lewis", - "teamMOYA", - "benedikt-wegmann", - "movq", - "bbirchnz", - "eddiwood", - "root0fall", - "calvinmorrow", - "UKayeF", - "Captain Cody", - "steveveepee", - "pedromagueija", - "parithon", - "TheCandianVendingMachine", - "bwRavencl", - "davidp57", - "Plob", - "Hawkmoon", - "alrik11es", - "Starfire13", - "Hornet2041/Lion", - "SgtFuzzle17", - "Doc_of_Mur", - "NickJZX", - "Sith1144", - "Raffson", - "zhexu14", - "ColonelAkirNakesh", - "Nosajthedevil", - "kivipe", - ] - text = ( - "

    DCS Liberation " - + VERSION - + "

    " - + "Source code : https://github.com/dcs-liberation/dcs_liberation" - + "

    Authors

    " - + "

    DCS Liberation was originally developed by shdwp, DCS Liberation 2.0 is a partial rewrite based on this work by Khopa." - "

    Contributors

    " - + ", ".join(contributors) - + "

    Special Thanks :

    " - "rp- for the pydcs framework
    " - "Grimes (mrSkortch) & Speed for the MIST framework
    " - "Ciribob for the JTACAutoLase.lua script
    " - "Walder for the Skynet-IADS script
    " - "Anubis Yinepu for the Hercules Cargo script
    " - 'Bug icons created by Freepik - Flaticon
    ' - 'Contains information from OpenStreetMap © OpenStreetMap contributors, which is made available here under the Open Database License (ODbL).
    ' - 'OpenStreetMap Data Extracts from Geofabrik
    ' - 'NASA EarthData
    ' - + "

    Splash Screen :

    " - + "Artwork by Andriy Dankovych (CC BY-SA) [https://www.facebook.com/AndriyDankovych]" - ) - about = QMessageBox() - about.setWindowTitle("About DCS Liberation") - about.setIcon(QMessageBox.Icon.Information) - about.setText(text) - logging.info(about.textFormat()) - about.exec_() - - def showLiberationDialog(self): - self.subwindow = QLiberationPreferencesWindow() - self.subwindow.show() - - def showSettingsDialog(self) -> None: - self.dialog = QSettingsWindow(self.game) - self.dialog.show() - - def showStatsDialog(self): - self.dialog = QStatsWindow(self.game) - self.dialog.show() - - def showNotesDialog(self): - self.dialog = QNotesWindow(self.game) - self.dialog.show() - - def showAirWingDialog(self) -> None: - self.dialog = AirWingDialog(self.game_model, self) - self.dialog.show() - - def showTransfersDialog(self) -> None: - self.dialog = PendingTransfersDialog(self.game_model) - self.dialog.show() - - def import_templates(self): - LAYOUTS.import_templates() - - def show_bug_report_dialog(self) -> None: - self.dialog = BugReportDialog(self) - self.dialog.show() - - def showLogsDialog(self): - self.dialog = QLogsWindow() - self.dialog.show() - - def onDebriefing(self, debrief: Debriefing): - logging.info("On Debriefing") - self.debriefing = QDebriefingWindow(debrief) - self.debriefing.exec() - - state = self.game.check_win_loss() - if state is not TurnState.CONTINUE: - GameOverDialog(won=state is TurnState.WIN, parent=self).exec() - else: - self.game.pass_turn() - GameUpdateSignal.get_instance().updateGame(self.game) - - def open_tgo_info_dialog(self, tgo: TheaterGroundObject) -> None: - QGroundObjectMenu(self, tgo, tgo.control_point, self.game).show() - - def open_control_point_info_dialog(self, cp: ControlPoint) -> None: - self._cp_dialog = QBaseMenu2(None, cp, self.game_model) - self._cp_dialog.show() - - def _disconnect_log_signals(self) -> None: - for handler in HookableInMemoryHandler.iter_registered_handlers(): - handler.clearHook() - - def _qsettings(self) -> QSettings: - return QSettings("DCS Liberation", "Qt UI") - - def _restore_window_geometry(self) -> None: - settings = self._qsettings() - self.restoreGeometry(settings.value("geometry")) - self.restoreState(settings.value("windowState")) - - def _save_window_geometry(self) -> None: - settings = self._qsettings() - settings.setValue("geometry", self.saveGeometry()) - settings.setValue("windowState", self.saveState()) - - def closeEvent(self, event: QCloseEvent) -> None: - result = QMessageBox.question( - self, - "Quit Liberation?", - "Are you sure you want to quit? All unsaved progress will be lost.", - QMessageBox.Yes | QMessageBox.No, - ) - if result == QMessageBox.Yes: - self._disconnect_log_signals() - self._save_window_geometry() - super().closeEvent(event) - self.dialog = None - for window in QApplication.topLevelWidgets(): - window.close() - else: - event.ignore() diff --git a/qt_ui/windows/QUnitInfoWindow.py b/qt_ui/windows/QUnitInfoWindow.py deleted file mode 100644 index b7a4e80a5..000000000 --- a/qt_ui/windows/QUnitInfoWindow.py +++ /dev/null @@ -1,124 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -from PySide6.QtCore import Qt -from PySide6.QtGui import QIcon, QPixmap -from PySide6.QtWidgets import QDialog, QFrame, QGridLayout, QLabel, QTextBrowser - -from game.dcs.aircrafttype import AircraftType -from game.dcs.groundunittype import GroundUnitType -from game.dcs.unittype import UnitType -from game.game import Game - -AIRCRAFT_BANNERS_BASE = Path("resources/ui/units/aircrafts/banners") -VEHICLE_BANNERS_BASE = Path("resources/ui/units/vehicles/banners") -MISSING_BANNER_PATH = AIRCRAFT_BANNERS_BASE / "Missing.jpg" - - -def aircraft_banner_for(unit_type: AircraftType) -> Path: - if unit_type.dcs_id in { - "Mirage-F1CT", - "Mirage-F1EE", - "Mirage-F1M-EE", - "Mirage-F1EQ", - }: - name = "Mirage-F1C-200" - elif unit_type.dcs_id in {"Mirage-F1CE", "Mirage-F1M-CE"}: - name = "Mirage-F1C" - elif unit_type.dcs_id == "F-15ESE": - name = "F-15E" - else: - name = unit_type.dcs_id - return AIRCRAFT_BANNERS_BASE / f"{name}.jpg" - - -def vehicle_banner_for(unit_type: GroundUnitType) -> Path: - return VEHICLE_BANNERS_BASE / f"{unit_type.dcs_id}.jpg" - - -def banner_path_for(unit_type: UnitType) -> Path: - if isinstance(unit_type, AircraftType): - return aircraft_banner_for(unit_type) - if isinstance(unit_type, GroundUnitType): - return vehicle_banner_for(unit_type) - raise NotImplementedError(f"Unhandled UnitType subclass: {unit_type.__class__}") - - -class QUnitInfoWindow(QDialog): - def __init__(self, game: Game, unit_type: UnitType) -> None: - super().__init__() - self.setModal(True) - self.game = game - self.unit_type = unit_type - self.name = unit_type.display_name - self.setWindowTitle(f"Unit Info: {self.name}") - self.setWindowIcon(QIcon("./resources/icon.png")) - self.setMinimumHeight(570) - self.setMaximumWidth(640) - self.setWindowFlags(Qt.WindowStaysOnTopHint) - - self.layout = QGridLayout() - - header = QLabel(self) - header.setGeometry(0, 0, 720, 360) - - banner_path = banner_path_for(unit_type) - if not banner_path.exists(): - banner_path = MISSING_BANNER_PATH - pixmap = QPixmap(banner_path) - header.setPixmap(pixmap.scaled(header.width(), header.height())) - self.layout.addWidget(header, 0, 0) - - self.gridLayout = QGridLayout() - - # Build the topmost details grid. - self.details_grid = QFrame() - self.details_grid_layout = QGridLayout() - self.details_grid_layout.setContentsMargins(0, 0, 0, 0) - - self.name_box = QLabel( - f"Name: {unit_type.manufacturer} {unit_type.display_name}" - ) - self.name_box.setProperty("style", "info-element") - - self.country_box = QLabel( - f"Country of Origin: {unit_type.country_of_origin}" - ) - self.country_box.setProperty("style", "info-element") - - self.role_box = QLabel(f"Role: {unit_type.role}") - self.role_box.setProperty("style", "info-element") - - self.year_box = QLabel( - f"Variant Introduction: {unit_type.year_introduced}" - ) - self.year_box.setProperty("style", "info-element") - - self.details_grid_layout.addWidget(self.name_box, 0, 0) - self.details_grid_layout.addWidget(self.country_box, 0, 1) - self.details_grid_layout.addWidget(self.role_box, 1, 0) - self.details_grid_layout.addWidget(self.year_box, 1, 1) - - self.details_grid.setLayout(self.details_grid_layout) - - self.gridLayout.addWidget(self.details_grid, 1, 0) - - # If it's an aircraft, include the task list. - if isinstance(unit_type, AircraftType): - tasks = ", ".join(str(t) for t in unit_type.iter_task_capabilities()) - self.tasks_box = QLabel(f"In-Game Tasks: {tasks}") - self.tasks_box.setProperty("style", "info-element") - self.gridLayout.addWidget(self.tasks_box, 2, 0) - - # Finally, add the description box. - self.details_text = QTextBrowser() - self.details_text.setProperty("style", "info-desc") - self.details_text.setText(unit_type.description) - self.details_text.setOpenExternalLinks( - True - ) # in aircrafttype.py and groundunittype.py, for the descriptions, if No Data. including a google search link - self.gridLayout.addWidget(self.details_text, 3, 0) - - self.layout.addLayout(self.gridLayout, 1, 0) - self.setLayout(self.layout) diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py deleted file mode 100644 index e861b911c..000000000 --- a/qt_ui/windows/QWaitingForMissionResultWindow.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import annotations - -import logging -from pathlib import Path -from typing import Optional, Callable - -from PySide6 import QtCore -from PySide6.QtCore import QObject, Signal -from PySide6.QtGui import QIcon, QMovie, QPixmap -from PySide6.QtWidgets import ( - QDialog, - QFileDialog, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QPushButton, - QTextBrowser, - QWidget, -) -from jinja2 import Environment, FileSystemLoader, select_autoescape - -from game import Game -from game.debriefing import Debriefing -from game.profiling import logged_duration -from qt_ui.simcontroller import SimController -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal - - -class DebriefingFileWrittenSignal(QObject): - instance = None - debriefingReceived = Signal(Debriefing) - - def __init__(self): - super(DebriefingFileWrittenSignal, self).__init__() - DebriefingFileWrittenSignal.instance = self - - def sendDebriefing(self, debriefing: Debriefing): - self.debriefingReceived.emit(debriefing) - - @staticmethod - def get_instance() -> DebriefingFileWrittenSignal: - return DebriefingFileWrittenSignal.instance - - -DebriefingFileWrittenSignal() - - -class QWaitingForMissionResultWindow(QDialog): - def __init__( - self, - game: Game, - sim_controller: SimController, - reset_to_pre_sim_checkpoint: Callable[[], None], - parent: Optional[QWidget] = None, - ) -> None: - super(QWaitingForMissionResultWindow, self).__init__(parent=parent) - self.setWindowModality(QtCore.Qt.WindowModal) - self.game = game - self.sim_controller = sim_controller - self.reset_to_pre_sim_checkpoint = reset_to_pre_sim_checkpoint - self.setWindowTitle("Waiting for mission completion.") - self.setWindowIcon(QIcon("./resources/icon.png")) - self.setMinimumHeight(570) - - self.initUi() - DebriefingFileWrittenSignal.get_instance().debriefingReceived.connect( - self.updateLayout - ) - self.wait_thread = sim_controller.wait_for_debriefing( - lambda debriefing: self.on_debriefing_update(debriefing) - ) - - def initUi(self): - self.layout = QGridLayout() - - header = QLabel(self) - header.setGeometry(0, 0, 655, 106) - pixmap = QPixmap("./resources/ui/conflict.png") - header.setPixmap(pixmap) - self.layout.addWidget(header, 0, 0) - - self.gridLayout = QGridLayout() - - jinja = Environment( - loader=FileSystemLoader("resources/ui/templates"), - autoescape=select_autoescape( - disabled_extensions=("",), - default_for_string=True, - default=True, - ), - trim_blocks=True, - lstrip_blocks=True, - ) - self.instructions_text = QTextBrowser() - self.instructions_text.setHtml( - jinja.get_template("mission_start_EN.j2").render() - ) - self.instructions_text.setOpenExternalLinks(True) - self.gridLayout.addWidget(self.instructions_text, 1, 0) - - progress = QLabel("") - progress.setAlignment(QtCore.Qt.AlignCenter) - progress_bar = QMovie("./resources/ui/loader.gif") - progress.setMovie(progress_bar) - - self.actions = QGroupBox("Actions :") - self.actions_layout = QHBoxLayout() - self.actions.setLayout(self.actions_layout) - - self.manually_submit = QPushButton("Manually Submit [Advanced users]") - self.manually_submit.clicked.connect(self.submit_manually) - self.actions_layout.addWidget(self.manually_submit) - self.cancel = QPushButton("Abort mission") - self.cancel.clicked.connect(self.reject) - self.actions_layout.addWidget(self.cancel) - self.gridLayout.addWidget(self.actions, 2, 0) - - self.actions2 = QGroupBox("Actions :") - self.actions2_layout = QHBoxLayout() - self.actions2.setLayout(self.actions2_layout) - self.manually_submit2 = QPushButton("Manually Submit [Advanced users]") - self.manually_submit2.clicked.connect(self.submit_manually) - self.actions2_layout.addWidget(self.manually_submit2) - self.cancel2 = QPushButton("Abort mission") - self.cancel2.clicked.connect(self.reject) - self.actions2_layout.addWidget(self.cancel2) - self.proceed = QPushButton("Accept results") - self.proceed.setProperty("style", "btn-success") - self.proceed.clicked.connect(self.process_debriefing) - self.actions2_layout.addWidget(self.proceed) - - progress_bar.start() - self.layout.addLayout(self.gridLayout, 1, 0) - self.setLayout(self.layout) - - def reject(self) -> None: - if self.game.settings.reload_pre_sim_checkpoint_on_abort: - self.reset_to_pre_sim_checkpoint() - super().reject() - - @staticmethod - def add_update_row(description: str, count: int, layout: QGridLayout) -> None: - row = layout.rowCount() - layout.addWidget(QLabel(f"{description}"), row, 0) - layout.addWidget(QLabel(f"{count}"), row, 1) - - def updateLayout(self, debriefing: Debriefing) -> None: - updateBox = QGroupBox("Mission status") - update_layout = QGridLayout() - updateBox.setLayout(update_layout) - self.debriefing = debriefing - - self.add_update_row( - "Aircraft destroyed", len(list(debriefing.air_losses.losses)), update_layout - ) - self.add_update_row( - "Front line units destroyed", - len(list(debriefing.front_line_losses)), - update_layout, - ) - self.add_update_row( - "Convoy units destroyed", len(list(debriefing.convoy_losses)), update_layout - ) - self.add_update_row( - "Shipping cargo destroyed", - len(list(debriefing.cargo_ship_losses)), - update_layout, - ) - self.add_update_row( - "Airlift cargo destroyed", - sum(len(loss.cargo) for loss in debriefing.airlift_losses), - update_layout, - ) - self.add_update_row( - "Ground Objects destroyed", - len(list(debriefing.ground_object_losses)), - update_layout, - ) - self.add_update_row( - "Scenery Objects destroyed", - len(list(debriefing.scenery_object_losses)), - update_layout, - ) - self.add_update_row( - "Base capture events", len(debriefing.base_captures), update_layout - ) - - # Clear previous content of the window - for i in reversed(range(self.gridLayout.count())): - try: - self.gridLayout.itemAt(i).widget().setParent(None) - except: - logging.exception("Failed to clear window") - - # Set new window content - self.gridLayout.addWidget(updateBox, 0, 0) - - if not debriefing.state_data.mission_ended: - self.gridLayout.addWidget(QLabel("Mission is being played"), 1, 0) - self.gridLayout.addWidget(self.actions, 2, 0) - else: - self.gridLayout.addWidget(QLabel("Mission is over"), 1, 0) - self.gridLayout.addWidget(self.actions2, 2, 0) - - def on_debriefing_update(self, debriefing: Debriefing) -> None: - try: - logging.info("On Debriefing update") - logging.debug(debriefing) - DebriefingFileWrittenSignal.get_instance().sendDebriefing(debriefing) - except Exception: - logging.exception("Got an error while sending debriefing") - if not debriefing.state_data.mission_ended: - # Wait for more changes - self.wait_thread = self.sim_controller.wait_for_debriefing( - lambda d: self.on_debriefing_update(d) - ) - - def process_debriefing(self): - with logged_duration("Turn processing"): - self.sim_controller.process_results(self.debriefing) - GameUpdateSignal.get_instance().sendDebriefing(self.debriefing) - self.accept() - - def closeEvent(self, evt): - super(QWaitingForMissionResultWindow, self).closeEvent(evt) - if self.wait_thread is not None: - self.wait_thread.stop() - - def submit_manually(self): - file = QFileDialog.getOpenFileName( - self, "Select game file to open", filter="json(*.json)", dir="." - ) - if file[0] != "": - logging.debug("Processing manually submitted %s", file[0]) - # Stop the current waiting thread as we manually submit the results - self.wait_thread.stop() - self.on_debriefing_update( - self.sim_controller.debrief_current_state(Path(file[0]), force_end=True) - ) diff --git a/qt_ui/windows/SquadronDialog.py b/qt_ui/windows/SquadronDialog.py deleted file mode 100644 index b8104e073..000000000 --- a/qt_ui/windows/SquadronDialog.py +++ /dev/null @@ -1,282 +0,0 @@ -import logging -from typing import Callable, Iterator, Optional - -from PySide6.QtCore import QItemSelection, QItemSelectionModel, QModelIndex, Qt -from PySide6.QtWidgets import ( - QAbstractItemView, - QCheckBox, - QComboBox, - QDialog, - QHBoxLayout, - QLabel, - QListView, - QPushButton, - QVBoxLayout, -) - -from game.ato.flighttype import FlightType -from game.squadrons import Pilot, Squadron -from game.theater import ConflictTheater, ControlPoint -from qt_ui.delegates import TwoColumnRowDelegate -from qt_ui.errorreporter import report_errors -from qt_ui.models import AtoModel, SquadronModel -from qt_ui.simcontroller import SimController -from qt_ui.widgets.combos.primarytaskselector import PrimaryTaskSelector - - -class PilotDelegate(TwoColumnRowDelegate): - def __init__(self, squadron_model: SquadronModel) -> None: - super().__init__(rows=2, columns=2, font_size=12) - self.squadron_model = squadron_model - - @staticmethod - def pilot(index: QModelIndex) -> Pilot: - return index.data(SquadronModel.PilotRole) - - def text_for(self, index: QModelIndex, row: int, column: int) -> str: - pilot = self.pilot(index) - if (row, column) == (0, 0): - return self.squadron_model.data(index, Qt.DisplayRole) - elif (row, column) == (0, 1): - flown = pilot.record.missions_flown - missions = "missions" if flown != 1 else "mission" - return f"{flown} {missions} flown" - elif (row, column) == (1, 0): - return "Player" if pilot.player else "AI" - elif (row, column) == (1, 1): - return pilot.status.value - return "" - - -class PilotList(QListView): - """List view for displaying a squadron's pilots.""" - - def __init__(self, squadron_model: SquadronModel) -> None: - super().__init__() - self.squadron_model = squadron_model - - self.setItemDelegate(PilotDelegate(self.squadron_model)) - self.setModel(self.squadron_model) - self.selectionModel().setCurrentIndex( - self.squadron_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select - ) - - # self.setIconSize(QSize(91, 24)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - - -class AutoAssignedTaskControls(QVBoxLayout): - def __init__(self, squadron_model: SquadronModel) -> None: - super().__init__() - self.squadron_model = squadron_model - - self.addWidget(QLabel("Auto-assignable mission types")) - - def make_callback(toggled_task: FlightType) -> Callable[[bool], None]: - def callback(checked: bool) -> None: - self.on_toggled(toggled_task, checked) - - return callback - - for task in FlightType: - if self.squadron_model.squadron.capable_of(task): - checkbox = QCheckBox(text=task.value) - checkbox.setChecked(squadron_model.is_auto_assignable(task)) - checkbox.toggled.connect(make_callback(task)) - self.addWidget(checkbox) - - self.addStretch() - - def on_toggled(self, task: FlightType, checked: bool) -> None: - self.squadron_model.set_auto_assignable(task, checked) - - -class SquadronDestinationComboBox(QComboBox): - def __init__(self, squadron: Squadron, theater: ConflictTheater) -> None: - super().__init__() - self.squadron = squadron - self.theater = theater - - room = squadron.location.unclaimed_parking() - self.addItem( - f"Remain at {squadron.location} (room for {room} more aircraft)", None - ) - selected_index: Optional[int] = None - for idx, destination in enumerate(sorted(self.iter_destinations(), key=str), 1): - if destination == squadron.destination: - selected_index = idx - room = destination.unclaimed_parking() - self.addItem( - f"Transfer to {destination} (room for {room} more aircraft)", - destination, - ) - - if squadron.destination is None: - selected_index = 0 - - if selected_index is not None: - self.setCurrentIndex(selected_index) - - def iter_destinations(self) -> Iterator[ControlPoint]: - size = self.squadron.expected_size_next_turn - for control_point in self.theater.control_points_for(self.squadron.player): - if control_point == self: - continue - if not control_point.can_operate(self.squadron.aircraft): - continue - if control_point.unclaimed_parking() < size: - continue - yield control_point - - -class SquadronDialog(QDialog): - """Dialog window showing a squadron.""" - - def __init__( - self, - ato_model: AtoModel, - squadron_model: SquadronModel, - theater: ConflictTheater, - sim_controller: SimController, - parent, - ) -> None: - super().__init__(parent) - self.ato_model = ato_model - self.squadron_model = squadron_model - self.sim_controller = sim_controller - - self.setMinimumSize(1000, 440) - self.setWindowTitle(str(squadron_model.squadron)) - # TODO: self.setWindowIcon() - - layout = QVBoxLayout() - self.setLayout(layout) - - columns = QHBoxLayout() - layout.addLayout(columns) - - left_column = QVBoxLayout() - columns.addLayout(left_column) - - left_column.addWidget(QLabel("Primary task")) - self.primary_task_selector = PrimaryTaskSelector.for_squadron( - self.squadron_model.squadron - ) - self.primary_task_selector.currentIndexChanged.connect( - self.on_task_index_changed - ) - left_column.addWidget(self.primary_task_selector) - - auto_assigned_tasks = AutoAssignedTaskControls(squadron_model) - left_column.addLayout(auto_assigned_tasks) - - self.pilot_list = PilotList(squadron_model) - self.pilot_list.selectionModel().selectionChanged.connect( - self.on_selection_changed - ) - columns.addWidget(self.pilot_list) - - button_panel = QHBoxLayout() - - self.transfer_destination = SquadronDestinationComboBox( - squadron_model.squadron, theater - ) - self.transfer_destination.currentIndexChanged.connect( - self.on_destination_changed - ) - button_panel.addWidget(self.transfer_destination) - - button_panel.addStretch() - layout.addLayout(button_panel) - - self.toggle_ai_button = QPushButton() - self.reset_ai_toggle_state(self.pilot_list.currentIndex()) - self.toggle_ai_button.setProperty("style", "start-button") - self.toggle_ai_button.clicked.connect(self.toggle_ai) - button_panel.addWidget(self.toggle_ai_button, alignment=Qt.AlignRight) - - self.toggle_leave_button = QPushButton() - self.reset_leave_toggle_state(self.pilot_list.currentIndex()) - self.toggle_leave_button.setProperty("style", "start-button") - self.toggle_leave_button.clicked.connect(self.toggle_leave) - button_panel.addWidget(self.toggle_leave_button, alignment=Qt.AlignRight) - - @property - def squadron(self) -> Squadron: - return self.squadron_model.squadron - - def on_destination_changed(self, index: int) -> None: - with report_errors("Could not change squadron destination", self): - destination = self.transfer_destination.itemData(index) - if destination is None: - self.squadron.cancel_relocation() - else: - self.squadron.plan_relocation( - destination, self.sim_controller.current_time_in_sim - ) - self.ato_model.replace_from_game(player=True) - - def check_disabled_button_states( - self, button: QPushButton, index: QModelIndex - ) -> bool: - if not index.isValid(): - button.setText("No pilot selected") - button.setDisabled(True) - return True - pilot = self.squadron_model.pilot_at_index(index) - if not pilot.alive: - button.setText("Pilot is dead") - button.setDisabled(True) - return True - return False - - def toggle_ai(self) -> None: - index = self.pilot_list.currentIndex() - if not index.isValid(): - logging.error("Cannot toggle player/AI: no pilot is selected") - return - self.squadron_model.toggle_ai_state(index) - - def reset_ai_toggle_state(self, index: QModelIndex) -> None: - if self.check_disabled_button_states(self.toggle_ai_button, index): - return - if not self.squadron_model.squadron.aircraft.flyable: - self.toggle_ai_button.setText("Not flyable") - self.toggle_ai_button.setDisabled(True) - return - self.toggle_ai_button.setEnabled(True) - pilot = self.squadron_model.pilot_at_index(index) - self.toggle_ai_button.setText( - "Convert to AI" if pilot.player else "Convert to player" - ) - - def toggle_leave(self) -> None: - index = self.pilot_list.currentIndex() - if not index.isValid(): - logging.error("Cannot toggle on leave state: no pilot is selected") - return - self.squadron_model.toggle_leave_state(index) - - def reset_leave_toggle_state(self, index: QModelIndex) -> None: - if self.check_disabled_button_states(self.toggle_leave_button, index): - return - pilot = self.squadron_model.pilot_at_index(index) - self.toggle_leave_button.setEnabled( - not pilot.on_leave or self.squadron_model.squadron.has_unfilled_pilot_slots - ) - self.toggle_leave_button.setText( - "Return from leave" if pilot.on_leave else "Send on leave" - ) - - def on_selection_changed( - self, selected: QItemSelection, _deselected: QItemSelection - ) -> None: - index = selected.indexes()[0] - self.reset_ai_toggle_state(index) - self.reset_leave_toggle_state(index) - - def on_task_index_changed(self, index: int) -> None: - task = self.primary_task_selector.itemData(index) - if task is None: - raise RuntimeError("Selected task cannot be None") - self.squadron.primary_task = task diff --git a/qt_ui/windows/basemenu/DepartingConvoysMenu.py b/qt_ui/windows/basemenu/DepartingConvoysMenu.py deleted file mode 100644 index f6963ce89..000000000 --- a/qt_ui/windows/basemenu/DepartingConvoysMenu.py +++ /dev/null @@ -1,102 +0,0 @@ -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QFrame, - QGridLayout, - QGroupBox, - QLabel, - QPushButton, - QScrollArea, - QVBoxLayout, - QWidget, -) - -from game.theater import ControlPoint -from game.transfers import MultiGroupTransport -from qt_ui.dialogs import Dialog -from qt_ui.models import GameModel -from qt_ui.uiconstants import VEHICLES_ICONS - - -class DepartingConvoyInfo(QGroupBox): - def __init__(self, convoy: MultiGroupTransport) -> None: - super().__init__(f"{convoy.name} to {convoy.destination}") - self.convoy = convoy - - main_layout = QVBoxLayout() - self.setLayout(main_layout) - - unit_layout = QGridLayout() - main_layout.addLayout(unit_layout) - - for idx, (unit_type, count) in enumerate(convoy.units.items()): - icon = QLabel() - if unit_type.dcs_id in VEHICLES_ICONS.keys(): - icon.setPixmap(VEHICLES_ICONS[unit_type.dcs_id]) - else: - icon.setText("" + unit_type.display_name + "") - icon.setProperty("style", "icon-armor") - unit_layout.addWidget(icon, idx, 0) - unit_layout.addWidget( - QLabel(f"{count} x {unit_type.display_name}"), - idx, - 1, - ) - - if not convoy.units: - unit_layout.addWidget(QLabel("/"), 0, 0) - - attack_button = QPushButton("Attack") - attack_button.setProperty("style", "btn-danger") - attack_button.setMaximumWidth(180) - attack_button.clicked.connect(self.on_attack) - main_layout.addWidget(attack_button, 0, Qt.AlignLeft) - - def on_attack(self): - # TODO: Maintain Convoy list in Game. - # The fact that we create these here makes some of the other bookkeeping - # complicated. We could instead generate this at the start of the turn (and - # update whenever transfers are created or canceled) and also use that time to - # precalculate things like the next stop and group names. - Dialog.open_new_package_dialog(self.convoy, parent=self.window()) - - -class DepartingConvoysList(QFrame): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super().__init__() - self.cp = cp - self.setMinimumWidth(500) - - layout = QVBoxLayout() - self.setLayout(layout) - - scroll_content = QWidget() - task_box_layout = QGridLayout() - scroll_content.setLayout(task_box_layout) - - for convoy in game_model.game.coalition_for( - cp.captured - ).transfers.convoys.departing_from(cp): - group_info = DepartingConvoyInfo(convoy) - task_box_layout.addWidget(group_info) - - for cargo_ship in game_model.game.coalition_for( - cp.captured - ).transfers.cargo_ships.departing_from(cp): - group_info = DepartingConvoyInfo(cargo_ship) - task_box_layout.addWidget(group_info) - - scroll_content.setLayout(task_box_layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - layout.addWidget(scroll) - - -class DepartingConvoysMenu(QFrame): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super().__init__() - layout = QVBoxLayout() - layout.addWidget(DepartingConvoysList(cp, game_model)) - self.setLayout(layout) diff --git a/qt_ui/windows/basemenu/NewUnitTransferDialog.py b/qt_ui/windows/basemenu/NewUnitTransferDialog.py deleted file mode 100644 index b93f2f4c9..000000000 --- a/qt_ui/windows/basemenu/NewUnitTransferDialog.py +++ /dev/null @@ -1,312 +0,0 @@ -from __future__ import annotations - -import logging -from collections import defaultdict -from typing import Callable, Dict, Type - -from PySide6.QtCore import Qt, Signal -from PySide6.QtWidgets import ( - QComboBox, - QDialog, - QFrame, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QPushButton, - QScrollArea, - QSizePolicy, - QSpacerItem, - QVBoxLayout, - QWidget, -) -from dcs.unittype import UnitType - -from game import Game -from game.dcs.groundunittype import GroundUnitType -from game.theater import ControlPoint -from game.transfers import TransferOrder -from qt_ui.models import GameModel -from qt_ui.widgets.QLabeledWidget import QLabeledWidget - - -class TransferDestinationComboBox(QComboBox): - def __init__(self, game: Game, origin: ControlPoint) -> None: - super().__init__() - self.game = game - self.origin = origin - - for cp in self.game.blue.transit_network.nodes: - if cp == origin: - continue - if not self.game.blue.transit_network.has_path_between(origin, cp): - continue - self.addItem(cp.name, cp) - self.model().sort(0) - self.setCurrentIndex(0) - - -class UnitTransferList(QFrame): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super().__init__(self) - self.cp = cp - self.game_model = game_model - - self.bought_amount_labels = {} - self.existing_units_labels = {} - - main_layout = QVBoxLayout() - self.setLayout(main_layout) - - scroll_content = QWidget() - task_box_layout = QGridLayout() - scroll_content.setLayout(task_box_layout) - - units_column = sorted(cp.base.armor, key=lambda u: u.display_name) - - count = 0 - for count, unit_type in enumerate(units_column): - self.add_purchase_row(unit_type, task_box_layout, count) - stretch = QVBoxLayout() - stretch.addStretch() - task_box_layout.addLayout(stretch, count, 0) - - scroll_content.setLayout(task_box_layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - main_layout.addWidget(scroll) - - -class TransferOptionsPanel(QVBoxLayout): - def __init__(self, game: Game, origin: ControlPoint) -> None: - super().__init__() - - self.source_combo_box = TransferDestinationComboBox(game, origin) - self.transport_type = QComboBox() - self.transport_type.addItem("Auto", "auto") - self.transport_type.addItem("Airlift", "airlift") - self.addLayout(QLabeledWidget("Destination:", self.source_combo_box)) - self.addLayout(QLabeledWidget("Requested transport type:", self.transport_type)) - - @property - def changed(self): - return self.source_combo_box.currentIndexChanged - - @property - def current(self) -> ControlPoint: - return self.source_combo_box.currentData() - - @property - def request_airlift(self) -> bool: - return self.transport_type.currentData() == "airlift" - - -class TransferControls(QGroupBox): - def __init__( - self, - increase_text: str, - on_increase: Callable[[TransferControls], None], - decrease_text: str, - on_decrease: Callable[[TransferControls], None], - initial_amount: int = 0, - disabled: bool = False, - ) -> None: - super().__init__() - - self.quantity = initial_amount - - self.setProperty("style", "buy-box") - self.setMaximumHeight(36) - self.setMinimumHeight(36) - layout = QHBoxLayout() - self.setLayout(layout) - - decrease = QPushButton(decrease_text) - decrease.setProperty("style", "btn-sell") - decrease.setDisabled(disabled) - decrease.setMinimumSize(16, 16) - decrease.setMaximumSize(16, 16) - decrease.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - decrease.clicked.connect(lambda: on_decrease(self)) - layout.addWidget(decrease) - - self.count_label = QLabel() - self.count_label.setSizePolicy( - QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - ) - self.set_quantity(initial_amount) - layout.addWidget(self.count_label) - - increase = QPushButton(increase_text) - increase.setProperty("style", "btn-buy") - increase.setDisabled(disabled) - increase.setMinimumSize(16, 16) - increase.setMaximumSize(16, 16) - increase.clicked.connect(lambda: on_increase(self)) - increase.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - layout.addWidget(increase) - - def set_quantity(self, quantity: int) -> None: - self.quantity = quantity - self.count_label.setText(f"{self.quantity}") - - -class ScrollingUnitTransferGrid(QFrame): - transfer_quantity_changed = Signal() - - def __init__(self, cp: ControlPoint, game_model: GameModel) -> None: - super().__init__() - self.cp = cp - self.game_model = game_model - self.transfers: Dict[Type[UnitType, int]] = defaultdict(int) - - main_layout = QVBoxLayout() - - scroll_content = QWidget() - task_box_layout = QGridLayout() - - unit_types = set(self.game_model.game.faction_for(player=True).ground_units) - sorted_units = sorted( - {u for u in unit_types if self.cp.base.total_units_of_type(u)}, - key=lambda u: u.display_name, - ) - for row, unit_type in enumerate(sorted_units): - self.add_unit_row(unit_type, task_box_layout, row) - stretch = QVBoxLayout() - stretch.addStretch() - task_box_layout.addLayout(stretch, task_box_layout.count(), 0) - - scroll_content.setLayout(task_box_layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - main_layout.addWidget(scroll) - self.setLayout(main_layout) - - def add_unit_row( - self, - unit_type: GroundUnitType, - layout: QGridLayout, - row: int, - ) -> None: - exist = QGroupBox() - exist.setProperty("style", "buy-box") - exist.setMaximumHeight(36) - exist.setMinimumHeight(36) - origin_inventory_layout = QHBoxLayout() - exist.setLayout(origin_inventory_layout) - - origin_inventory = self.cp.base.total_units_of_type(unit_type) - - unit_name = QLabel(f"{unit_type.display_name}") - unit_name.setSizePolicy( - QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - ) - - origin_inventory_label = QLabel(str(origin_inventory)) - origin_inventory_label.setSizePolicy( - QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - ) - - def increase(controls: TransferControls): - nonlocal origin_inventory - nonlocal origin_inventory_label - if not origin_inventory: - return - - self.transfers[unit_type] += 1 - origin_inventory -= 1 - controls.set_quantity(self.transfers[unit_type]) - origin_inventory_label.setText(str(origin_inventory)) - self.transfer_quantity_changed.emit() - - def decrease(controls: TransferControls): - nonlocal origin_inventory - nonlocal origin_inventory_label - if not controls.quantity: - return - - self.transfers[unit_type] -= 1 - origin_inventory += 1 - controls.set_quantity(self.transfers[unit_type]) - origin_inventory_label.setText(str(origin_inventory)) - self.transfer_quantity_changed.emit() - - transfer_controls = TransferControls("->", increase, "<-", decrease) - - origin_inventory_layout.addWidget(unit_name) - origin_inventory_layout.addItem( - QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum) - ) - origin_inventory_layout.addWidget(origin_inventory_label) - origin_inventory_layout.addItem( - QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum) - ) - - layout.addWidget(exist, row, 1) - layout.addWidget(transfer_controls, row, 2) - - -class NewUnitTransferDialog(QDialog): - def __init__( - self, - game_model: GameModel, - origin: ControlPoint, - parent=None, - ) -> None: - super().__init__(parent) - self.origin = origin - self.setWindowTitle(f"New unit transfer from {origin.name}") - - self.game_model = game_model - - layout = QVBoxLayout() - self.setLayout(layout) - - self.dest_panel = TransferOptionsPanel(game_model.game, origin) - layout.addLayout(self.dest_panel) - - self.transfer_panel = ScrollingUnitTransferGrid(origin, game_model) - self.transfer_panel.transfer_quantity_changed.connect( - self.on_transfer_quantity_changed - ) - layout.addWidget(self.transfer_panel) - - self.submit_button = QPushButton("Create Transfer Order", parent=self) - self.submit_button.clicked.connect(self.on_submit) - self.submit_button.setProperty("style", "start-button") - self.submit_button.setDisabled(True) - layout.addWidget(self.submit_button) - - def on_submit(self) -> None: - destination = self.dest_panel.current - transfers = {} - for unit_type, count in self.transfer_panel.transfers.items(): - if not count: - continue - - logging.info( - f"Transferring {count} {unit_type} from {self.origin} to " - f"{destination}" - ) - transfers[unit_type] = count - - transfer = TransferOrder( - origin=self.origin, - destination=destination, - units=transfers, - request_airflift=self.dest_panel.request_airlift, - ) - self.game_model.transfer_model.new_transfer( - transfer, self.game_model.sim_controller.current_time_in_sim - ) - self.close() - - def on_transfer_quantity_changed(self) -> None: - has_transfer_items = any(self.transfer_panel.transfers.values()) - self.submit_button.setDisabled(not has_transfer_items) diff --git a/qt_ui/windows/basemenu/QBaseMenu2.py b/qt_ui/windows/basemenu/QBaseMenu2.py deleted file mode 100644 index f93d33a10..000000000 --- a/qt_ui/windows/basemenu/QBaseMenu2.py +++ /dev/null @@ -1,317 +0,0 @@ -import textwrap - -from PySide6.QtCore import Qt -from PySide6.QtGui import QCloseEvent, QPixmap -from PySide6.QtWidgets import ( - QDialog, - QHBoxLayout, - QLabel, - QMessageBox, - QPushButton, - QVBoxLayout, - QWidget, -) - -from game import Game -from game.ato.flighttype import FlightType -from game.config import RUNWAY_REPAIR_COST -from game.server import EventStream -from game.theater import ( - AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION, - ControlPoint, - ControlPointType, - FREE_FRONTLINE_UNIT_SUPPLY, -) -from qt_ui.cheatcontext import game_state_modifying_cheat_context -from qt_ui.dialogs import Dialog -from qt_ui.models import GameModel -from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.basemenu.NewUnitTransferDialog import NewUnitTransferDialog -from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs -from qt_ui.windows.basemenu.UnitTransactionFrame import UnitTransactionFrame - - -class QBaseMenu2(QDialog): - def __init__(self, parent, cp: ControlPoint, game_model: GameModel): - super(QBaseMenu2, self).__init__(parent) - - # Attrs - self.cp = cp - self.game_model = game_model - self.objectName = "menuDialogue" - - if self.cp.captured: - self.deliveryEvent = None - - self.setWindowIcon(EVENT_ICONS["capture"]) - - self.setWindowFlags(Qt.WindowStaysOnTopHint) - self.setMinimumSize(300, 200) - self.setMinimumWidth(1024) - self.setMaximumWidth(1024) - self.setModal(True) - - self.setWindowTitle(self.cp.name) - - base_menu_header = QWidget() - top_layout = QHBoxLayout() - - header = QLabel(self) - header.setGeometry(0, 0, 655, 106) - pixmap = QPixmap(self.get_base_image()) - header.setPixmap(pixmap) - - description_layout = QVBoxLayout() - top_layout.addLayout(description_layout) - - title = QLabel("" + self.cp.name + "") - title.setAlignment(Qt.AlignLeft | Qt.AlignTop) - title.setProperty("style", "base-title") - description_layout.addWidget(title) - - if self.cp.ferry_only: - description_layout.addWidget( - QLabel( - "
    ".join( - textwrap.wrap( - "This base only supports ferry missions. Transfer the " - "squadrons to a different base to use them.", - width=80, - ) - ) - ) - ) - - description_layout.addStretch() - - self.intel_summary = QLabel() - self.intel_summary.setToolTip(self.generate_intel_tooltip()) - self.update_intel_summary() - top_layout.addWidget(self.intel_summary) - top_layout.setAlignment(Qt.AlignTop) - - runway_buttons_layout = QVBoxLayout() - top_layout.addLayout(runway_buttons_layout) - - if ( - self.cp.runway_is_destroyable - and self.game_model.game.settings.enable_runway_state_cheat - ): - self.cheat_runway_state = QPushButton() - self.update_cheat_runway_state_text() - self.cheat_runway_state.clicked.connect(self.on_cheat_runway_state) - runway_buttons_layout.addWidget(self.cheat_runway_state) - - self.repair_button = QPushButton() - self.repair_button.clicked.connect(self.begin_runway_repair) - self.update_repair_button() - runway_buttons_layout.addWidget(self.repair_button) - runway_buttons_layout.addStretch() - - base_menu_header.setProperty("style", "baseMenuHeader") - base_menu_header.setLayout(top_layout) - - main_layout = QVBoxLayout() - main_layout.addWidget(header) - main_layout.addWidget(base_menu_header) - main_layout.addWidget(QBaseMenuTabs(cp, self.game_model)) - bottom_row = QHBoxLayout() - main_layout.addLayout(bottom_row) - - if FlightType.OCA_RUNWAY in self.cp.mission_types(for_player=True): - runway_attack_button = QPushButton("Attack airfield") - bottom_row.addWidget(runway_attack_button) - - runway_attack_button.setProperty("style", "btn-danger") - runway_attack_button.clicked.connect(self.new_package) - - if self.cp.captured and self.has_transfer_destinations: - transfer_button = QPushButton("Transfer Units") - transfer_button.setProperty("style", "btn-success") - bottom_row.addWidget(transfer_button) - transfer_button.clicked.connect(self.open_transfer_dialog) - - if self.cheat_capturable: - capture_button = QPushButton("CHEAT: Capture") - capture_button.setProperty("style", "btn-danger") - bottom_row.addWidget(capture_button) - capture_button.clicked.connect(self.cheat_capture) - - self.budget_display = QLabel( - UnitTransactionFrame.BUDGET_FORMAT.format(self.game_model.game.blue.budget) - ) - self.budget_display.setAlignment(Qt.AlignRight | Qt.AlignBottom) - self.budget_display.setProperty("style", "budget-label") - bottom_row.addWidget(self.budget_display) - GameUpdateSignal.get_instance().budgetupdated.connect(self.update_budget) - self.setLayout(main_layout) - - @property - def cheat_capturable(self) -> bool: - return self.game_model.game.settings.enable_base_capture_cheat - - def cheat_capture(self) -> None: - with game_state_modifying_cheat_context(self.game_model.game) as events: - self.cp.capture( - self.game_model.game, events, for_player=not self.cp.captured - ) - self.close() - - @property - def has_transfer_destinations(self) -> bool: - return self.game_model.game.transit_network_for( - self.cp.captured - ).has_destinations(self.cp) - - def update_cheat_runway_state_text(self) -> None: - if self.cp.runway_can_be_repaired: - self.cheat_runway_state.setText("CHEAT: Repair runway") - else: - self.cheat_runway_state.setText("CHEAT: Destroy runway") - - def on_cheat_runway_state(self) -> None: - if self.cp.runway_can_be_repaired: - self.cp.runway_status.repair() - else: - self.cp.runway_status.damage() - self.update_cheat_runway_state_text() - self.update_repair_button() - self.update_intel_summary() - with EventStream.event_context() as events: - events.update_control_point(self.cp) - - @property - def can_repair_runway(self) -> bool: - return self.cp.captured and self.cp.runway_can_be_repaired - - @property - def can_afford_runway_repair(self) -> bool: - return self.game_model.game.blue.budget >= RUNWAY_REPAIR_COST - - def begin_runway_repair(self) -> None: - if not self.can_afford_runway_repair: - QMessageBox.critical( - self, - "Cannot repair runway", - f"Runway repair costs ${RUNWAY_REPAIR_COST}M but you have " - f"only ${self.game_model.game.blue.budget}M available.", - QMessageBox.Ok, - ) - return - if not self.can_repair_runway: - QMessageBox.critical( - self, - "Cannot repair runway", - f"Cannot repair this runway.", - QMessageBox.Ok, - ) - return - - self.cp.begin_runway_repair() - self.game_model.game.blue.budget -= RUNWAY_REPAIR_COST - self.update_repair_button() - self.update_intel_summary() - GameUpdateSignal.get_instance().updateGame(self.game_model.game) - - def update_repair_button(self) -> None: - self.repair_button.setVisible(True) - turns_remaining = self.cp.runway_status.repair_turns_remaining - if self.cp.captured and turns_remaining is not None: - self.repair_button.setText("Repairing...") - self.repair_button.setDisabled(True) - return - - if self.can_repair_runway: - if self.can_afford_runway_repair: - self.repair_button.setText(f"Repair ${RUNWAY_REPAIR_COST}M") - self.repair_button.setDisabled(False) - return - else: - self.repair_button.setText( - f"Cannot afford repair ${RUNWAY_REPAIR_COST}M" - ) - self.repair_button.setDisabled(True) - return - - self.repair_button.setVisible(False) - self.repair_button.setDisabled(True) - - def update_intel_summary(self) -> None: - aircraft = self.cp.allocated_aircraft().total_present - parking = self.cp.total_aircraft_parking - ground_unit_limit = self.cp.frontline_unit_count_limit - deployable_unit_info = "" - - allocated = self.cp.allocated_ground_units( - self.game_model.game.coalition_for(self.cp.captured).transfers - ) - unit_overage = max( - allocated.total_present - self.cp.frontline_unit_count_limit, 0 - ) - if self.cp.has_active_frontline: - deployable_unit_info = ( - f" (Up to {ground_unit_limit} deployable, {unit_overage} reserve)" - ) - - intel_lines = [ - f"{aircraft}/{parking} aircraft", - f"{self.cp.base.total_armor} ground units" + deployable_unit_info, - f"{allocated.total_transferring} more ground units en route, {allocated.total_ordered} ordered", - ] - if (runway_description := self.cp.describe_runway_status()) is not None: - intel_lines.append(runway_description) - intel_lines.extend( - [ - f"{self.cp.active_ammo_depots_count}/{self.cp.total_ammo_depots_count} ammo depots", - f"{'Factory can produce units' if self.cp.has_factory else 'Does not have a factory'}", - ] - ) - - self.intel_summary.setText("\n".join(intel_lines)) - - def generate_intel_tooltip(self) -> str: - tooltip = ( - f"Deployable unit limit ({self.cp.frontline_unit_count_limit}) = {FREE_FRONTLINE_UNIT_SUPPLY} (base) + " - f" {AMMO_DEPOT_FRONTLINE_UNIT_CONTRIBUTION} (per connected ammo depot) * {self.cp.total_ammo_depots_count} " - f"(depots)" - ) - - if self.cp.has_active_frontline: - unit_overage = max( - self.cp.base.total_armor - self.cp.frontline_unit_count_limit, 0 - ) - tooltip += ( - f"\n{unit_overage} units will be held in reserve and will not be deployed to " - f"connected frontlines for this turn" - ) - - return tooltip - - def closeEvent(self, close_event: QCloseEvent): - GameUpdateSignal.get_instance().updateGame(self.game_model.game) - - def get_base_image(self): - if ( - self.cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP - or self.cp.cptype == ControlPointType.LHA_GROUP - ): - carrier_type = self.cp.get_carrier_group_type(always_supercarrier=True) - return f"./resources/ui/units/ships/{carrier_type.id}.png" - elif self.cp.cptype == ControlPointType.FOB and self.cp.has_helipads: - return "./resources/ui/heliport.png" - elif self.cp.cptype == ControlPointType.FOB: - return "./resources/ui/fob.png" - else: - return "./resources/ui/airbase.png" - - def new_package(self) -> None: - Dialog.open_new_package_dialog(self.cp, parent=self.window()) - - def open_transfer_dialog(self) -> None: - NewUnitTransferDialog(self.game_model, self.cp, parent=self.window()).show() - - def update_budget(self, game: Game) -> None: - self.budget_display.setText( - UnitTransactionFrame.BUDGET_FORMAT.format(game.blue.budget) - ) diff --git a/qt_ui/windows/basemenu/QBaseMenuTabs.py b/qt_ui/windows/basemenu/QBaseMenuTabs.py deleted file mode 100644 index a20cabf9f..000000000 --- a/qt_ui/windows/basemenu/QBaseMenuTabs.py +++ /dev/null @@ -1,34 +0,0 @@ -from PySide6.QtWidgets import QTabWidget - -from game.theater import ControlPoint, Fob -from qt_ui.models import GameModel -from qt_ui.windows.basemenu.DepartingConvoysMenu import DepartingConvoysMenu -from qt_ui.windows.basemenu.airfield.QAirfieldCommand import QAirfieldCommand -from qt_ui.windows.basemenu.ground_forces.QGroundForcesHQ import QGroundForcesHQ -from qt_ui.windows.basemenu.intel.QIntelInfo import QIntelInfo - - -class QBaseMenuTabs(QTabWidget): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super(QBaseMenuTabs, self).__init__() - - if not cp.captured: - self.intel = QIntelInfo(cp) - self.addTab(self.intel, "Intel") - - self.departing_convoys = DepartingConvoysMenu(cp, game_model) - self.addTab(self.departing_convoys, "Departing Convoys") - return - - if isinstance(cp, Fob): - self.ground_forces_hq = QGroundForcesHQ(cp, game_model) - self.addTab(self.ground_forces_hq, "Ground Forces HQ") - if cp.helipads: - self.airfield_command = QAirfieldCommand(cp, game_model) - self.addTab(self.airfield_command, "Heliport") - else: - self.airfield_command = QAirfieldCommand(cp, game_model) - self.addTab(self.airfield_command, "Airfield Command") - if cp.can_deploy_ground_units: - self.ground_forces_hq = QGroundForcesHQ(cp, game_model) - self.addTab(self.ground_forces_hq, "Ground Forces HQ") diff --git a/qt_ui/windows/basemenu/UnitTransactionFrame.py b/qt_ui/windows/basemenu/UnitTransactionFrame.py deleted file mode 100644 index bdf14f282..000000000 --- a/qt_ui/windows/basemenu/UnitTransactionFrame.py +++ /dev/null @@ -1,279 +0,0 @@ -from __future__ import annotations - -import logging -from enum import Enum -from typing import Generic, TypeVar - -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QApplication, - QFrame, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QLayout, - QMessageBox, - QPushButton, - QSizePolicy, - QSpacerItem, -) - -from game.purchaseadapter import PurchaseAdapter, TransactionError -from qt_ui.models import GameModel -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.QUnitInfoWindow import QUnitInfoWindow - - -class RecruitType(Enum): - BUY = 0 - SELL = 1 - - -TransactionItemType = TypeVar("TransactionItemType") - - -class PurchaseGroup(QGroupBox, Generic[TransactionItemType]): - def __init__( - self, - item: TransactionItemType, - recruiter: UnitTransactionFrame[TransactionItemType], - ) -> None: - super().__init__() - self.item = item - self.recruiter = recruiter - - self.setProperty("style", "buy-box") - self.setMaximumHeight(72) - self.setMinimumHeight(36) - layout = QHBoxLayout() - self.setLayout(layout) - - self.sell_button = QPushButton("-") - self.sell_button.setProperty("style", "btn-sell") - self.sell_button.setDisabled(not recruiter.enable_sale(item)) - self.sell_button.setMinimumSize(16, 16) - self.sell_button.setMaximumSize(16, 16) - self.sell_button.setSizePolicy( - QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - ) - - self.sell_button.clicked.connect( - lambda: self.recruiter.recruit_handler(RecruitType.SELL, self.item) - ) - - self.amount_bought = QLabel() - self.amount_bought.setSizePolicy( - QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - ) - - self.buy_button = QPushButton("+") - self.buy_button.setProperty("style", "btn-buy") - self.buy_button.setDisabled(not recruiter.enable_purchase(item)) - self.buy_button.setMinimumSize(16, 16) - self.buy_button.setMaximumSize(16, 16) - - self.buy_button.clicked.connect( - lambda: self.recruiter.recruit_handler(RecruitType.BUY, self.item) - ) - self.buy_button.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - - layout.addWidget(self.sell_button) - layout.addWidget(self.amount_bought) - layout.addWidget(self.buy_button) - - self.update_state() - - @property - def pending_units(self) -> int: - return self.recruiter.pending_delivery_quantity(self.item) - - def update_state(self) -> None: - self.buy_button.setEnabled(self.recruiter.enable_purchase(self.item)) - self.buy_button.setToolTip( - self.recruiter.purchase_tooltip(self.buy_button.isEnabled()) - ) - self.sell_button.setEnabled(self.recruiter.enable_sale(self.item)) - self.sell_button.setToolTip( - self.recruiter.sell_tooltip(self.sell_button.isEnabled()) - ) - self.amount_bought.setText(f"{self.pending_units}") - - -class UnitTransactionFrame(QFrame, Generic[TransactionItemType]): - BUDGET_FORMAT = "Available Budget: ${:.2f}M" - - def __init__( - self, - game_model: GameModel, - purchase_adapter: PurchaseAdapter[TransactionItemType], - ) -> None: - super().__init__() - self.game_model = game_model - self.purchase_adapter = purchase_adapter - self.existing_units_labels = {} - self.purchase_groups: dict[ - TransactionItemType, PurchaseGroup[TransactionItemType] - ] = {} - self.update_available_budget() - - def current_quantity_of(self, item: TransactionItemType) -> int: - return self.purchase_adapter.current_quantity_of(item) - - def pending_delivery_quantity(self, item: TransactionItemType) -> int: - return self.purchase_adapter.pending_delivery_quantity(item) - - def expected_quantity_next_turn(self, item: TransactionItemType) -> int: - return self.purchase_adapter.expected_quantity_next_turn(item) - - def display_name_of( - self, item: TransactionItemType, multiline: bool = False - ) -> str: - return self.purchase_adapter.name_of(item, multiline) - - def price_of(self, item: TransactionItemType) -> int: - return self.purchase_adapter.price_of(item) - - @property - def budget(self) -> float: - return self.game_model.game.blue.budget - - @budget.setter - def budget(self, value: int) -> None: - self.game_model.game.blue.budget = value - - def add_purchase_row( - self, - item: TransactionItemType, - layout: QGridLayout, - row: int, - ) -> None: - exist = QGroupBox() - exist.setProperty("style", "buy-box") - exist.setMaximumHeight(72) - exist.setMinimumHeight(36) - existLayout = QHBoxLayout() - existLayout.setSizeConstraint(QLayout.SetMinimumSize) - exist.setLayout(existLayout) - - existing_units = self.current_quantity_of(item) - - unitName = QLabel(f"{self.display_name_of(item, multiline=True)}") - unitName.setSizePolicy( - QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - ) - - existing_units = QLabel(str(existing_units)) - existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - - self.existing_units_labels[item] = existing_units - - price = QLabel(f"$ {self.price_of(item)} M") - price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - - purchase_group = PurchaseGroup(item, self) - self.purchase_groups[item] = purchase_group - - info = QGroupBox() - info.setProperty("style", "buy-box") - info.setMaximumHeight(72) - info.setMinimumHeight(36) - infolayout = QHBoxLayout() - info.setLayout(infolayout) - - unitInfo = QPushButton("i") - unitInfo.setProperty("style", "btn-info") - unitInfo.setMinimumSize(16, 16) - unitInfo.setMaximumSize(16, 16) - unitInfo.clicked.connect(lambda: self.info(item)) - unitInfo.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - - existLayout.addWidget(unitName) - existLayout.addItem( - QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum) - ) - existLayout.addWidget(existing_units) - existLayout.addItem( - QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum) - ) - existLayout.addWidget(price) - - infolayout.addWidget(unitInfo) - - layout.addWidget(exist, row, 1) - layout.addWidget(purchase_group, row, 2) - layout.addWidget(info, row, 3) - - def update_available_budget(self) -> None: - GameUpdateSignal.get_instance().updateBudget(self.game_model.game) - - def recruit_handler( - self, recruit_type: RecruitType, item: TransactionItemType - ) -> None: - # Lookup if Keyboard Modifiers were pressed - # Shift = 10 times - # CTRL = 5 Times - modifiers = QApplication.keyboardModifiers() - if modifiers == Qt.ShiftModifier: - amount = 10 - elif modifiers == Qt.ControlModifier: - amount = 5 - else: - amount = 1 - - if recruit_type == RecruitType.SELL: - self.sell(item, amount) - elif recruit_type == RecruitType.BUY: - self.buy(item, amount) - - def post_transaction_update(self) -> None: - self.update_purchase_controls() - self.update_available_budget() - - def buy(self, item: TransactionItemType, quantity: int) -> None: - try: - self.purchase_adapter.buy(item, quantity) - except TransactionError as ex: - logging.exception(f"Purchase of {self.display_name_of(item)} failed") - QMessageBox.warning(self, "Purchase failed", str(ex), QMessageBox.Ok) - finally: - self.post_transaction_update() - - def sell(self, item: TransactionItemType, quantity: int) -> None: - try: - self.purchase_adapter.sell(item, quantity) - except TransactionError as ex: - logging.exception(f"Sale of {self.display_name_of(item)} failed") - QMessageBox.warning(self, "Sale failed", str(ex), QMessageBox.Ok) - finally: - self.post_transaction_update() - - def update_purchase_controls(self) -> None: - for group in self.purchase_groups.values(): - group.update_state() - - def enable_purchase(self, item: TransactionItemType) -> bool: - return self.purchase_adapter.can_buy(item) - - def enable_sale(self, item: TransactionItemType) -> bool: - return self.purchase_adapter.can_sell_or_cancel(item) - - @staticmethod - def purchase_tooltip(is_enabled: bool) -> str: - if is_enabled: - return "Buy unit. Use Shift or Ctrl key to buy multiple units at once." - else: - return "Unit can not be bought." - - @staticmethod - def sell_tooltip(is_enabled: bool) -> str: - if is_enabled: - return "Sell unit. Use Shift or Ctrl key to buy multiple units at once." - else: - return "Unit can not be sold." - - def info(self, item: TransactionItemType) -> None: - self.info_window = QUnitInfoWindow( - self.game_model.game, self.purchase_adapter.unit_type_of(item) - ) - self.info_window.show() diff --git a/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py b/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py deleted file mode 100644 index 64b1f89d5..000000000 --- a/qt_ui/windows/basemenu/airfield/QAircraftRecruitmentMenu.py +++ /dev/null @@ -1,114 +0,0 @@ -from typing import Set - -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QGridLayout, - QHBoxLayout, - QLabel, - QScrollArea, - QVBoxLayout, - QWidget, -) - -from game.dcs.aircrafttype import AircraftType -from game.purchaseadapter import AircraftPurchaseAdapter -from game.squadrons import Squadron -from game.theater import ControlPoint -from qt_ui.models import GameModel -from qt_ui.uiconstants import ICONS -from qt_ui.windows.basemenu.UnitTransactionFrame import UnitTransactionFrame - - -class QAircraftRecruitmentMenu(UnitTransactionFrame[Squadron]): - def __init__(self, cp: ControlPoint, game_model: GameModel) -> None: - super().__init__(game_model, AircraftPurchaseAdapter(cp)) - self.cp = cp - self.game_model = game_model - self.purchase_groups = {} - self.bought_amount_labels = {} - self.existing_units_labels = {} - - self.bought_amount_labels = {} - self.existing_units_labels = {} - - self.hangar_status = QHangarStatus(game_model, self.cp) - - main_layout = QVBoxLayout() - - scroll_content = QWidget() - task_box_layout = QGridLayout() - row = 0 - - unit_types: Set[AircraftType] = set() - - for squadron in cp.squadrons: - unit_types.add(squadron.aircraft) - - sorted_squadrons = sorted( - cp.squadrons, key=lambda s: (s.aircraft.display_name, s.name) - ) - for row, squadron in enumerate(sorted_squadrons): - self.add_purchase_row(squadron, task_box_layout, row) - - stretch = QVBoxLayout() - stretch.addStretch() - task_box_layout.addLayout(stretch, row, 0) - - scroll_content.setLayout(task_box_layout) - scroll = QScrollArea() - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - main_layout.addLayout(self.hangar_status) - main_layout.addWidget(scroll) - self.setLayout(main_layout) - - def sell_tooltip(self, is_enabled: bool) -> str: - if is_enabled: - return "Sell unit. Use Shift or Ctrl key to sell multiple units at once." - else: - return ( - "Can not be sold because either no aircraft are available or are " - "already assigned to a mission." - ) - - def post_transaction_update(self) -> None: - super().post_transaction_update() - self.hangar_status.update_label() - - -class QHangarStatus(QHBoxLayout): - def __init__(self, game_model: GameModel, control_point: ControlPoint) -> None: - super().__init__() - self.game_model = game_model - self.control_point = control_point - - self.icon = QLabel() - self.icon.setPixmap(ICONS["Hangar"]) - self.text = QLabel("") - - self.update_label() - self.addWidget(self.icon, Qt.AlignLeft) - self.addWidget(self.text, Qt.AlignLeft) - self.addStretch(50) - self.setAlignment(Qt.AlignLeft) - - def update_label(self) -> None: - next_turn = self.control_point.allocated_aircraft() - max_amount = self.control_point.total_aircraft_parking - - components = [f"{next_turn.total_present} present"] - if next_turn.total_ordered > 0: - components.append(f"{next_turn.total_ordered} purchased") - elif next_turn.total_ordered < 0: - components.append(f"{-next_turn.total_ordered} sold") - - transferring = next_turn.total_transferring - if transferring > 0: - components.append(f"{transferring} transferring in") - if transferring < 0: - components.append(f"{-transferring} transferring out") - - details = ", ".join(components) - self.text.setText( - f"{next_turn.total}/{max_amount} ({details})" - ) diff --git a/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py b/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py deleted file mode 100644 index 78a679618..000000000 --- a/qt_ui/windows/basemenu/airfield/QAirfieldCommand.py +++ /dev/null @@ -1,40 +0,0 @@ -from PySide6.QtWidgets import QFrame, QGroupBox, QHBoxLayout, QLabel, QVBoxLayout - -from game.theater import ControlPoint -from qt_ui.models import GameModel -from qt_ui.windows.basemenu.airfield.QAircraftRecruitmentMenu import ( - QAircraftRecruitmentMenu, -) -from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView - - -class QAirfieldCommand(QFrame): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super(QAirfieldCommand, self).__init__() - self.cp = cp - self.game_model = game_model - self.init_ui() - - def init_ui(self): - wrapper_layout = QVBoxLayout() - layout = QHBoxLayout() - wrapper_layout.addLayout(layout) - - layout.addWidget(QAircraftRecruitmentMenu(self.cp, self.game_model), stretch=5) - - planned = QGroupBox("Planned Flights") - planned_layout = QVBoxLayout() - planned_layout.addWidget(QPlannedFlightsView(self.game_model, self.cp)) - planned.setLayout(planned_layout) - layout.addWidget(planned, stretch=3) - - wrapper_layout.addWidget( - QLabel( - "Purchasing aircraft at this airbase requires squadrons to be present. " - "To transfer additional squadrons to this airbase, open
    " - "the air wing menu, double click the squadron to transfer, then select " - "the transfer destination." - ) - ) - - self.setLayout(wrapper_layout) diff --git a/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py b/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py deleted file mode 100644 index 07ef03d9d..000000000 --- a/qt_ui/windows/basemenu/ground_forces/QArmorRecruitmentMenu.py +++ /dev/null @@ -1,49 +0,0 @@ -from PySide6.QtCore import Qt -from PySide6.QtWidgets import QGridLayout, QScrollArea, QVBoxLayout, QWidget - -from game.dcs.groundunittype import GroundUnitType -from game.purchaseadapter import GroundUnitPurchaseAdapter -from game.theater import ControlPoint -from qt_ui.models import GameModel -from qt_ui.windows.basemenu.UnitTransactionFrame import UnitTransactionFrame - - -class QArmorRecruitmentMenu(UnitTransactionFrame[GroundUnitType]): - def __init__(self, cp: ControlPoint, game_model: GameModel): - super().__init__( - game_model, - GroundUnitPurchaseAdapter( - cp, game_model.game.coalition_for(cp.captured), game_model.game - ), - ) - self.cp = cp - self.game_model = game_model - self.purchase_groups = {} - self.bought_amount_labels = {} - self.existing_units_labels = {} - - main_layout = QVBoxLayout() - - scroll_content = QWidget() - task_box_layout = QGridLayout() - scroll_content.setLayout(task_box_layout) - row = 0 - - unit_types = list( - set(self.game_model.game.faction_for(player=True).ground_units) - ) - unit_types.sort(key=lambda u: u.display_name) - for row, unit_type in enumerate(unit_types): - self.add_purchase_row(unit_type, task_box_layout, row) - stretch = QVBoxLayout() - stretch.addStretch() - task_box_layout.addLayout(stretch, row, 0) - - scroll_content.setLayout(task_box_layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - main_layout.addWidget(scroll) - self.setLayout(main_layout) diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py deleted file mode 100644 index ec963c82e..000000000 --- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesHQ.py +++ /dev/null @@ -1,24 +0,0 @@ -from PySide6.QtWidgets import QFrame, QGridLayout - -from game.theater import ControlPoint -from qt_ui.models import GameModel -from qt_ui.windows.basemenu.ground_forces.QArmorRecruitmentMenu import ( - QArmorRecruitmentMenu, -) -from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategy import ( - QGroundForcesStrategy, -) - - -class QGroundForcesHQ(QFrame): - def __init__(self, cp: ControlPoint, game_model: GameModel) -> None: - super(QGroundForcesHQ, self).__init__() - self.cp = cp - self.game_model = game_model - self.init_ui() - - def init_ui(self): - layout = QGridLayout() - layout.addWidget(QArmorRecruitmentMenu(self.cp, self.game_model), 0, 0) - layout.addWidget(QGroundForcesStrategy(self.cp, self.game_model.game), 0, 1) - self.setLayout(layout) diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py deleted file mode 100644 index ac37e7c6c..000000000 --- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategy.py +++ /dev/null @@ -1,61 +0,0 @@ -from collections.abc import Callable - -from PySide6.QtWidgets import QGroupBox, QLabel, QPushButton, QVBoxLayout - -from game import Game -from game.theater import ControlPoint -from qt_ui.cheatcontext import game_state_modifying_cheat_context -from qt_ui.windows.basemenu.ground_forces.QGroundForcesStrategySelector import ( - QGroundForcesStrategySelector, -) - - -class QGroundForcesStrategy(QGroupBox): - def __init__(self, cp: ControlPoint, game: Game): - super(QGroundForcesStrategy, self).__init__("Frontline operations :") - self.cp = cp - self.game = game - self.init_ui() - - def init_ui(self): - def make_cheat_callback( - enemy_point: ControlPoint, advance: bool - ) -> Callable[[], None]: - def cheat() -> None: - self.cheat_alter_front_line(enemy_point, advance) - - return cheat - - layout = QVBoxLayout() - for enemy_cp in self.cp.connected_points: - if not enemy_cp.captured: - layout.addWidget(QLabel(enemy_cp.name)) - layout.addWidget(QGroundForcesStrategySelector(self.cp, enemy_cp)) - if self.game.settings.enable_frontline_cheats: - advance_button = QPushButton("CHEAT: Advance") - advance_button.setProperty("style", "btn-danger") - layout.addWidget(advance_button) - advance_button.clicked.connect( - make_cheat_callback(enemy_cp, advance=True) - ) - - retreat_button = QPushButton("CHEAT: Retreat") - retreat_button.setProperty("style", "btn-danger") - layout.addWidget(retreat_button) - retreat_button.clicked.connect( - make_cheat_callback(enemy_cp, advance=False) - ) - - layout.addStretch() - self.setLayout(layout) - - def cheat_alter_front_line(self, enemy_point: ControlPoint, advance: bool) -> None: - with game_state_modifying_cheat_context(self.game) as events: - amount = 0.2 - if not advance: - amount *= -1 - self.cp.base.affect_strength(amount) - enemy_point.base.affect_strength(-amount) - front_line = self.cp.front_line_with(enemy_point) - front_line.update_position() - events.update_front_line(front_line) diff --git a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py b/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py deleted file mode 100644 index e206ad1b4..000000000 --- a/qt_ui/windows/basemenu/ground_forces/QGroundForcesStrategySelector.py +++ /dev/null @@ -1,24 +0,0 @@ -from PySide6.QtWidgets import QComboBox - -from game.theater import CombatStance, ControlPoint - - -class QGroundForcesStrategySelector(QComboBox): - def __init__(self, cp: ControlPoint, enemy_cp: ControlPoint): - super(QGroundForcesStrategySelector, self).__init__() - self.cp = cp - self.enemy_cp = enemy_cp - - if enemy_cp.id not in self.cp.stances: - self.cp.stances[enemy_cp.id] = CombatStance.DEFENSIVE - - for i, stance in enumerate(CombatStance): - self.addItem(stance.name, userData=stance) - if self.cp.stances[enemy_cp.id] == stance: - self.setCurrentIndex(i) - - self.currentTextChanged.connect(self.on_change) - - def on_change(self): - print(self.currentData()) - self.cp.stances[self.enemy_cp.id] = self.currentData() diff --git a/qt_ui/windows/basemenu/intel/QIntelInfo.py b/qt_ui/windows/basemenu/intel/QIntelInfo.py deleted file mode 100644 index c2a0408b0..000000000 --- a/qt_ui/windows/basemenu/intel/QIntelInfo.py +++ /dev/null @@ -1,62 +0,0 @@ -from collections import defaultdict - -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QFrame, - QGridLayout, - QGroupBox, - QLabel, - QVBoxLayout, - QScrollArea, - QWidget, -) - -from game.theater import ControlPoint - - -class QIntelInfo(QFrame): - def __init__(self, cp: ControlPoint): - super(QIntelInfo, self).__init__() - self.cp = cp - - layout = QVBoxLayout() - scroll_content = QWidget() - intel_layout = QVBoxLayout() - - units_by_task: dict[str, dict[str, int]] = defaultdict(lambda: defaultdict(int)) - for unit_type, count in self.cp.allocated_aircraft().present.items(): - if count: - task_type = unit_type.dcs_unit_type.task_default.name - units_by_task[task_type][unit_type.display_name] += count - - units_by_task = { - task: units_by_task[task] for task in sorted(units_by_task.keys()) - } - - front_line_units = defaultdict(int) - for unit_type, count in self.cp.base.armor.items(): - if count: - front_line_units[unit_type.display_name] += count - - units_by_task["Front line units"] = front_line_units - for task, unit_types in units_by_task.items(): - task_group = QGroupBox(task) - task_layout = QGridLayout() - task_group.setLayout(task_layout) - - for row, (name, count) in enumerate(unit_types.items()): - task_layout.addWidget(QLabel(f"{name}"), row, 0) - task_layout.addWidget(QLabel(str(count)), row, 1) - - intel_layout.addWidget(task_group) - - scroll_content.setLayout(intel_layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - - layout.addWidget(scroll) - - self.setLayout(layout) diff --git a/qt_ui/windows/finances/QFinancesMenu.py b/qt_ui/windows/finances/QFinancesMenu.py deleted file mode 100644 index a09b8eed8..000000000 --- a/qt_ui/windows/finances/QFinancesMenu.py +++ /dev/null @@ -1,111 +0,0 @@ -import itertools -from typing import Optional - -from PySide6.QtWidgets import ( - QDialog, - QFrame, - QGridLayout, - QLabel, - QSizePolicy, -) - -import qt_ui.uiconstants as CONST -from game.game import Game -from game.income import BuildingIncome, Income -from game.theater import ControlPoint - - -class QHorizontalSeparationLine(QFrame): - def __init__(self): - super().__init__() - self.setMinimumWidth(1) - self.setFixedHeight(20) - self.setFrameShape(QFrame.HLine) - self.setFrameShadow(QFrame.Sunken) - self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) - - -class FinancesLayout(QGridLayout): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - self.row = itertools.count(0) - - income = Income(game, player) - - self.add_total(game, income, player) - self.add_line() - - control_points = reversed( - sorted(income.control_points, key=lambda c: c.income_per_turn) - ) - for control_point in control_points: - self.add_control_point(control_point) - - self.add_line() - - buildings = reversed(sorted(income.buildings, key=lambda b: b.income)) - for building in buildings: - self.add_building(building) - - self.setRowStretch(next(self.row), 1) - - def add_total(self, game, income, player): - self.add_row( - middle=f"Income multiplier: {income.multiplier:.1f}", - right=f"{income.total:.1f}M", - ) - budget = game.coalition_for(player).budget - self.add_row(middle="Balance", right=f"{budget:.1f}M") - - def add_row( - self, - left: Optional[str] = None, - middle: Optional[str] = None, - right: Optional[str] = None, - ) -> None: - if not any([left, middle, right]): - raise ValueError - - row = next(self.row) - if left is not None: - self.addWidget(QLabel(left), row, 0) - if middle is not None: - self.addWidget(QLabel(middle), row, 1) - if right is not None: - self.addWidget(QLabel(right), row, 2) - - def add_control_point(self, control_point: ControlPoint) -> None: - self.add_row( - left=f"{control_point.name}", - right=f"{control_point.income_per_turn}M", - ) - - def add_building(self, building: BuildingIncome) -> None: - row = next(self.row) - self.addWidget( - QLabel(f"{building.category.upper()} [{building.name}]"), row, 0 - ) - self.addWidget( - QLabel(f"{building.number} buildings x {building.income_per_building}M"), - row, - 1, - ) - rlabel = QLabel(f"{building.income}M") - rlabel.setProperty("style", "green") - self.addWidget(rlabel, row, 2) - - def add_line(self) -> None: - self.addWidget(QHorizontalSeparationLine(), next(self.row), 0, 1, 3) - - -class QFinancesMenu(QDialog): - def __init__(self, game: Game): - super(QFinancesMenu, self).__init__() - - self.game = game - self.setModal(True) - self.setWindowTitle("Finances") - self.setWindowIcon(CONST.ICONS["Money"]) - self.setMinimumSize(450, 200) - - self.setLayout(FinancesLayout(game, player=True)) diff --git a/qt_ui/windows/gameoverdialog.py b/qt_ui/windows/gameoverdialog.py deleted file mode 100644 index 78ae24bf0..000000000 --- a/qt_ui/windows/gameoverdialog.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import annotations - -from PySide6.QtWidgets import ( - QDialog, - QVBoxLayout, - QLabel, - QHBoxLayout, - QPushButton, - QWidget, -) - -from qt_ui.windows.newgame.QNewGameWizard import NewGameWizard - - -class GameOverDialog(QDialog): - def __init__(self, won: bool, parent: QWidget | None = None) -> None: - super().__init__(parent) - self.setModal(True) - self.setWindowTitle("Game Over") - - layout = QVBoxLayout() - self.setLayout(layout) - - layout.addWidget( - QLabel( - f"You {'won' if won else 'lost'}!
    " - "
    " - "Click below to start a new game." - ) - ) - button_row = QHBoxLayout() - layout.addLayout(button_row) - - button_row.addStretch() - - new_game = QPushButton("New Game") - new_game.clicked.connect(self.on_new_game) - button_row.addWidget(new_game) - - def on_new_game(self) -> None: - wizard = NewGameWizard(self) - wizard.show() - wizard.accepted.connect(self.accept) diff --git a/qt_ui/windows/groundobject/QBuildingInfo.py b/qt_ui/windows/groundobject/QBuildingInfo.py deleted file mode 100644 index e47c7be95..000000000 --- a/qt_ui/windows/groundobject/QBuildingInfo.py +++ /dev/null @@ -1,45 +0,0 @@ -import os - -from PySide6.QtGui import QPixmap -from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout -from game.theater import TheaterUnit - -from game.config import REWARDS - - -class QBuildingInfo(QGroupBox): - def __init__(self, building: TheaterUnit, ground_object): - super(QBuildingInfo, self).__init__() - self.building = building - self.ground_object = ground_object - self.init_ui() - - def init_ui(self): - self.header = QLabel() - path = os.path.join( - "./resources/ui/units/buildings/" + self.building.icon + ".png" - ) - if not self.building.alive: - pixmap = QPixmap("./resources/ui/units/buildings/dead.png") - elif os.path.isfile(path): - pixmap = QPixmap(path) - else: - pixmap = QPixmap("./resources/ui/units/buildings/missing.png") - self.header.setPixmap(pixmap) - self.name = QLabel(self.building.short_name) - self.name.setProperty("style", "small") - layout = QVBoxLayout() - layout.addWidget(self.header) - layout.addWidget(self.name) - - if self.ground_object.category in REWARDS: - income_label_text = ( - "Value: " + str(REWARDS[self.ground_object.category]) + "M" - ) - if not self.building.alive: - income_label_text = "" + income_label_text + "" - self.reward = QLabel(income_label_text) - layout.addWidget(self.reward) - - footer = QHBoxLayout() - self.setLayout(layout) diff --git a/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py b/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py deleted file mode 100644 index 647ac060b..000000000 --- a/qt_ui/windows/groundobject/QGroundObjectBuyMenu.py +++ /dev/null @@ -1,351 +0,0 @@ -import logging -from collections import defaultdict -from dataclasses import dataclass, field -from typing import Type - -from PySide6.QtCore import Signal -from PySide6.QtGui import Qt -from PySide6.QtWidgets import ( - QCheckBox, - QComboBox, - QDialog, - QGridLayout, - QGroupBox, - QLabel, - QPushButton, - QSpinBox, - QVBoxLayout, - QWidget, -) -from dcs.unittype import UnitType - -from game import Game -from game.armedforces.forcegroup import ForceGroup -from game.data.groups import GroupRole, GroupTask -from game.layout.layout import ( - LayoutException, - TgoLayout, - TgoLayoutUnitGroup, -) -from game.theater import TheaterGroundObject -from game.theater.theatergroundobject import ( - EwrGroundObject, - SamGroundObject, - VehicleGroupGroundObject, -) -from qt_ui.uiconstants import EVENT_ICONS - - -@dataclass -class QTgoLayoutGroup: - layout: TgoLayoutUnitGroup - dcs_unit_type: Type[UnitType] - amount: int - unit_price: int - enabled: bool = True - - @property - def price(self) -> int: - return self.amount * self.unit_price if self.enabled else 0 - - -@dataclass -class QTgoLayout: - layout: TgoLayout - force_group: ForceGroup - groups: dict[str, list[QTgoLayoutGroup]] = field(default_factory=dict) - - @property - def price(self) -> int: - return sum(group.price for groups in self.groups.values() for group in groups) - - -class QTgoLayoutGroupRow(QWidget): - group_template_changed = Signal() - - def __init__(self, force_group: ForceGroup, group: TgoLayoutUnitGroup) -> None: - super().__init__() - self.grid_layout = QGridLayout() - self.setLayout(self.grid_layout) - self.grid_layout.setColumnStretch(0, 100) - self.amount_selector = QSpinBox() - self.unit_selector = QComboBox() - self.unit_selector.setMinimumWidth(250) - self.group_selector = QCheckBox() - - # Add all possible units with the price - for unit_type in force_group.unit_types_for_group(group): - self.unit_selector.addItem( - f"{unit_type.display_name} [${unit_type.price}M]", - userData=(unit_type.dcs_unit_type, unit_type.price), - ) - # Add all possible statics with price = 0 - for static_type in force_group.statics_for_group(group): - self.unit_selector.addItem( - f"{static_type} (Static)", userData=(static_type, 0) - ) - - if self.unit_selector.count() == 0: - raise LayoutException("No units available for the TgoLayoutGroup") - - self.unit_selector.adjustSize() - self.unit_selector.setEnabled(self.unit_selector.count() > 1) - self.grid_layout.addWidget(self.unit_selector, 0, 0, alignment=Qt.AlignRight) - self.grid_layout.addWidget(self.amount_selector, 0, 1, alignment=Qt.AlignRight) - - dcs_unit_type, price = self.unit_selector.itemData( - self.unit_selector.currentIndex() - ) - - self.group_layout = QTgoLayoutGroup( - group, dcs_unit_type, group.group_size, price - ) - - self.group_selector.setChecked(self.group_layout.enabled) - self.group_selector.setEnabled(self.group_layout.layout.optional) - - self.amount_selector.setMinimum(1) - self.amount_selector.setMaximum(self.group_layout.layout.max_size) - self.amount_selector.setValue(self.group_layout.amount) - self.amount_selector.setEnabled(self.group_layout.layout.max_size > 1) - - self.grid_layout.addWidget(self.group_selector, 0, 2, alignment=Qt.AlignRight) - - self.amount_selector.valueChanged.connect(self.on_group_changed) - self.unit_selector.currentIndexChanged.connect(self.on_group_changed) - self.group_selector.stateChanged.connect(self.on_group_changed) - - def on_group_changed(self) -> None: - self.group_layout.enabled = self.group_selector.isChecked() - unit_type, price = self.unit_selector.itemData( - self.unit_selector.currentIndex() - ) - self.group_layout.dcs_unit_type = unit_type - self.group_layout.unit_price = price - self.group_layout.amount = self.amount_selector.value() - self.group_template_changed.emit() - - -class QGroundObjectTemplateLayout(QGroupBox): - close_dialog_signal = Signal() - - def __init__( - self, - game: Game, - ground_object: TheaterGroundObject, - layout: QTgoLayout, - layout_changed_signal: Signal(QTgoLayout), - current_group_value: int, - ): - super().__init__() - # Connect to the signal to handle template updates - self.game = game - self.ground_object = ground_object - self.layout_changed_signal = layout_changed_signal - self.layout_model = layout - self.layout_changed_signal.connect(self.load_for_layout) - - self.current_group_value = current_group_value - - self.buy_button = QPushButton("Buy") - self.buy_button.setEnabled(False) - self.buy_button.clicked.connect(self.buy_group) - - self.template_layout = QGridLayout() - self.setLayout(self.template_layout) - - self.template_grid = QGridLayout() - self.template_layout.addLayout(self.template_grid, 0, 0, 1, 2) - self.template_layout.addWidget(self.buy_button, 1, 1) - stretch = QVBoxLayout() - stretch.addStretch() - self.template_layout.addLayout(stretch, 2, 0) - - # Load Layout - self.load_for_layout(self.layout_model) - - def load_for_layout(self, layout: QTgoLayout) -> None: - self.layout_model = layout - # Clean the current grid - self.layout_model.groups = defaultdict(list) - for id in range(self.template_grid.count()): - self.template_grid.itemAt(id).widget().deleteLater() - for group in self.layout_model.layout.groups: - self.add_theater_group( - group.group_name, self.layout_model.force_group, group.unit_groups - ) - self.group_template_changed() - - @property - def cost(self) -> int: - return self.layout_model.price - self.current_group_value - - @property - def affordable(self) -> bool: - return self.cost <= self.game.blue.budget - - def add_theater_group( - self, group_name: str, force_group: ForceGroup, groups: list[TgoLayoutUnitGroup] - ) -> None: - group_box = QGroupBox(group_name) - vbox_layout = QVBoxLayout() - for group in groups: - try: - group_row = QTgoLayoutGroupRow(force_group, group) - except LayoutException: - continue - self.layout_model.groups[group_name].append(group_row.group_layout) - group_row.group_template_changed.connect(self.group_template_changed) - vbox_layout.addWidget(group_row) - group_box.setLayout(vbox_layout) - self.template_grid.addWidget(group_box) - - def group_template_changed(self) -> None: - price = self.layout_model.price - self.buy_button.setText(f"Buy [${price}M][-${self.current_group_value}M]") - self.buy_button.setEnabled(self.affordable) - if self.buy_button.isEnabled(): - self.buy_button.setToolTip(f"Buy the group for ${self.cost}M") - else: - self.buy_button.setToolTip("Not enough money to buy this group") - - def buy_group(self) -> None: - if not self.affordable: - # Something went wrong. Buy button should be disabled! - logging.error("Not enough money to buy the group") - return - - # Change the heading of the new group to head to the conflict - self.ground_object.heading = ( - self.game.theater.heading_to_conflict_from(self.ground_object.position) - or self.ground_object.heading - ) - self.game.blue.budget -= self.cost - self.ground_object.groups = [] - for group_name, groups in self.layout_model.groups.items(): - for group in groups: - if group.enabled: - self.layout_model.force_group.create_theater_group_for_tgo( - self.ground_object, - group.layout, - f"{self.ground_object.name} ({group_name})", - self.game, - group.dcs_unit_type, # Forced Type - group.amount, # Forced Amount - ) - self.close_dialog_signal.emit() - - -class QGroundObjectBuyMenu(QDialog): - layout_changed_signal = Signal(QTgoLayout) - - def __init__( - self, - parent: QWidget, - ground_object: TheaterGroundObject, - game: Game, - current_group_value: int, - ) -> None: - super().__init__(parent) - - self.setMinimumWidth(350) - - self.setWindowTitle("Buy ground object @ " + ground_object.obj_name) - self.setWindowIcon(EVENT_ICONS["capture"]) - - self.mainLayout = QGridLayout() - self.setLayout(self.mainLayout) - - self.force_group_selector = QComboBox() - self.force_group_selector.setMinimumWidth(250) - self.layout_selector = QComboBox() - self.layout_selector.setMinimumWidth(250) - - # Get the layouts and fill the combobox - tasks = [] - if isinstance(ground_object, SamGroundObject): - role = GroupRole.AIR_DEFENSE - elif isinstance(ground_object, VehicleGroupGroundObject): - role = GroupRole.GROUND_FORCE - elif isinstance(ground_object, EwrGroundObject): - role = GroupRole.AIR_DEFENSE - tasks.append(GroupTask.EARLY_WARNING_RADAR) - else: - raise NotImplementedError(f"Unhandled TGO type {ground_object.__class__}") - - if not tasks: - tasks = role.tasks - - for group in game.blue.armed_forces.groups_for_tasks(tasks): - self.force_group_selector.addItem(group.name, userData=group) - self.force_group_selector.setEnabled(self.force_group_selector.count() > 1) - self.force_group_selector.adjustSize() - force_group = self.force_group_selector.itemData( - self.force_group_selector.currentIndex() - ) - - for layout in force_group.layouts: - self.layout_selector.addItem(layout.name, userData=layout) - self.layout_selector.adjustSize() - self.layout_selector.setEnabled(len(force_group.layouts) > 1) - selected_template = self.layout_selector.itemData( - self.layout_selector.currentIndex() - ) - - self.theater_layout = QTgoLayout(selected_template, force_group) - - self.layout_selector.currentIndexChanged.connect(self.layout_changed) - self.force_group_selector.currentIndexChanged.connect(self.force_group_changed) - - template_selector_layout = QGridLayout() - template_selector_layout.addWidget( - QLabel("Armed Forces Group:"), 0, 0, Qt.AlignLeft - ) - template_selector_layout.addWidget( - self.force_group_selector, 0, 1, alignment=Qt.AlignRight - ) - template_selector_layout.addWidget(QLabel("Layout:"), 1, 0, Qt.AlignLeft) - template_selector_layout.addWidget( - self.layout_selector, 1, 1, alignment=Qt.AlignRight - ) - self.mainLayout.addLayout(template_selector_layout, 0, 0) - - self.template_layout = QGroundObjectTemplateLayout( - game, - ground_object, - self.theater_layout, - self.layout_changed_signal, - current_group_value, - ) - self.template_layout.close_dialog_signal.connect(self.close_dialog) - self.mainLayout.addWidget(self.template_layout, 1, 0) - self.setLayout(self.mainLayout) - - def force_group_changed(self) -> None: - # Prevent ComboBox from firing change Events - self.layout_selector.blockSignals(True) - unit_group = self.force_group_selector.itemData( - self.force_group_selector.currentIndex() - ) - self.layout_selector.clear() - for layout in unit_group.layouts: - self.layout_selector.addItem(layout.name, userData=layout) - self.layout_selector.adjustSize() - # Enable if more than one template is available - self.layout_selector.setEnabled(len(unit_group.layouts) > 1) - # Enable Combobox Signals again - self.layout_selector.blockSignals(False) - self.layout_changed() - - def layout_changed(self) -> None: - self.layout() - self.theater_layout.layout = self.layout_selector.itemData( - self.layout_selector.currentIndex() - ) - self.theater_layout.force_group = self.force_group_selector.itemData( - self.force_group_selector.currentIndex() - ) - self.layout_changed_signal.emit(self.theater_layout) - - def close_dialog(self) -> None: - self.accept() diff --git a/qt_ui/windows/groundobject/QGroundObjectMenu.py b/qt_ui/windows/groundobject/QGroundObjectMenu.py deleted file mode 100644 index 09cc92518..000000000 --- a/qt_ui/windows/groundobject/QGroundObjectMenu.py +++ /dev/null @@ -1,279 +0,0 @@ -import logging - -from PySide6.QtGui import QTransform -from PySide6.QtWidgets import ( - QDialog, - QGridLayout, - QGroupBox, - QHBoxLayout, - QLabel, - QPushButton, - QVBoxLayout, - QSpinBox, - QWidget, -) -from dcs import Point - -from game import Game -from game.config import REWARDS -from game.data.building_data import FORTIFICATION_BUILDINGS -from game.server import EventStream -from game.sim.gameupdateevents import GameUpdateEvents -from game.theater import ControlPoint, TheaterGroundObject -from game.theater.theatergroundobject import ( - BuildingGroundObject, -) -from game.utils import Heading -from qt_ui.uiconstants import EVENT_ICONS, ICONS -from qt_ui.widgets.QBudgetBox import QBudgetBox -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.groundobject.QBuildingInfo import QBuildingInfo -from qt_ui.windows.groundobject.QGroundObjectBuyMenu import QGroundObjectBuyMenu - - -class HeadingIndicator(QLabel): - def __init__(self, initial_heading: Heading, parent: QWidget) -> None: - super().__init__(parent) - self.set_heading(initial_heading) - self.setFixedSize(32, 32) - - def set_heading(self, heading: Heading) -> None: - self.setPixmap( - ICONS["heading"].transformed(QTransform().rotate(heading.degrees)) - ) - - -class QGroundObjectMenu(QDialog): - def __init__( - self, - parent, - ground_object: TheaterGroundObject, - cp: ControlPoint, - game: Game, - ): - super().__init__(parent) - self.setMinimumWidth(350) - self.ground_object = ground_object - self.cp = cp - self.game = game - self.setWindowTitle( - f"Location - {self.ground_object.obj_name} ({self.cp.name})" - ) - self.setWindowIcon(EVENT_ICONS["capture"]) - self.intelBox = QGroupBox("Units :") - self.buildingBox = QGroupBox("Buildings :") - self.orientationBox = QGroupBox("Orientation :") - self.intelLayout = QGridLayout() - self.buildingsLayout = QGridLayout() - self.sell_all_button = None - self.total_value = 0 - self.init_ui() - - def init_ui(self): - self.mainLayout = QVBoxLayout() - self.budget = QBudgetBox(self.game) - self.budget.setGame(self.game) - - self.doLayout() - - if isinstance(self.ground_object, BuildingGroundObject): - self.mainLayout.addWidget(self.buildingBox) - if self.cp.captured: - self.mainLayout.addWidget(self.financesBox) - else: - self.mainLayout.addWidget(self.intelBox) - self.mainLayout.addWidget(self.orientationBox) - - self.actionLayout = QHBoxLayout() - - self.sell_all_button = QPushButton("Disband (+" + str(self.total_value) + "M)") - self.sell_all_button.clicked.connect(self.sell_all) - self.sell_all_button.setProperty("style", "btn-danger") - - self.buy_replace = QPushButton("Buy/Replace") - self.buy_replace.clicked.connect(self.buy_group) - self.buy_replace.setProperty("style", "btn-success") - - if self.ground_object.purchasable: - if self.total_value > 0: - self.actionLayout.addWidget(self.sell_all_button) - self.actionLayout.addWidget(self.buy_replace) - - if self.cp.captured and self.ground_object.purchasable: - self.mainLayout.addLayout(self.actionLayout) - self.setLayout(self.mainLayout) - - def doLayout(self): - self.update_total_value() - self.intelBox = QGroupBox("Units :") - self.intelLayout = QGridLayout() - i = 0 - for g in self.ground_object.groups: - for unit in g.units: - self.intelLayout.addWidget( - QLabel(f"Unit {str(unit.display_name)}"), i, 0 - ) - - if not unit.alive and unit.repairable and self.cp.captured: - price = unit.unit_type.price if unit.unit_type else 0 - repair = QPushButton(f"Repair [{price}M]") - repair.setProperty("style", "btn-success") - repair.clicked.connect( - lambda u=unit, p=price: self.repair_unit(u, p) - ) - self.intelLayout.addWidget(repair, i, 1) - i += 1 - - stretch = QVBoxLayout() - stretch.addStretch() - self.intelLayout.addLayout(stretch, i, 0) - - self.buildingBox = QGroupBox("Buildings :") - self.buildingsLayout = QGridLayout() - - j = 0 - total_income = 0 - received_income = 0 - for static in self.ground_object.statics: - if static not in FORTIFICATION_BUILDINGS: - self.buildingsLayout.addWidget( - QBuildingInfo(static, self.ground_object), j / 3, j % 3 - ) - j = j + 1 - - if self.ground_object.category in REWARDS.keys(): - total_income += REWARDS[self.ground_object.category] - if static.alive: - received_income += REWARDS[self.ground_object.category] - else: - logging.warning(self.ground_object.category + " not in REWARDS") - - self.financesBox = QGroupBox("Finances: ") - self.financesBoxLayout = QGridLayout() - self.financesBoxLayout.addWidget( - QLabel("Available: " + str(total_income) + "M"), 2, 1 - ) - self.financesBoxLayout.addWidget( - QLabel("Receiving: " + str(received_income) + "M"), 2, 2 - ) - - # Orientation Box - self.orientationBox = QGroupBox("Orientation :") - self.orientationBoxLayout = QHBoxLayout() - - self.heading_image = HeadingIndicator(self.ground_object.heading, self) - self.orientationBoxLayout.addWidget(self.heading_image) - self.headingLabel = QLabel("Heading:") - self.orientationBoxLayout.addWidget(self.headingLabel) - self.headingSelector = QSpinBox() - self.headingSelector.setEnabled(self.cp.is_friendly(to_player=True)) - self.headingSelector.setRange(0, 359) - self.headingSelector.setWrapping(True) - self.headingSelector.setSingleStep(5) - self.headingSelector.setValue(self.ground_object.heading.degrees) - self.headingSelector.valueChanged.connect( - lambda degrees: self.rotate_tgo(Heading(degrees)) - ) - self.orientationBoxLayout.addWidget(self.headingSelector) - if self.cp.captured: - self.head_to_conflict_button = QPushButton("Head to conflict") - heading = ( - self.game.theater.heading_to_conflict_from(self.ground_object.position) - or self.ground_object.heading - ) - self.head_to_conflict_button.clicked.connect( - lambda: self.headingSelector.setValue(heading.degrees) - ) - self.orientationBoxLayout.addWidget(self.head_to_conflict_button) - else: - self.headingSelector.setEnabled(False) - - # Set the layouts - self.financesBox.setLayout(self.financesBoxLayout) - self.buildingBox.setLayout(self.buildingsLayout) - self.intelBox.setLayout(self.intelLayout) - self.orientationBox.setLayout(self.orientationBoxLayout) - - def do_refresh_layout(self): - try: - for i in reversed(range(self.mainLayout.count())): - item = self.mainLayout.itemAt(i) - if item is not None and item.widget() is not None: - item.widget().setParent(None) - self.sell_all_button.setParent(None) - self.buy_replace.setParent(None) - self.actionLayout.setParent(None) - - self.doLayout() - if isinstance(self.ground_object, BuildingGroundObject): - self.mainLayout.addWidget(self.buildingBox) - else: - self.mainLayout.addWidget(self.intelBox) - self.mainLayout.addWidget(self.orientationBox) - - self.actionLayout = QHBoxLayout() - if self.total_value > 0: - self.actionLayout.addWidget(self.sell_all_button) - self.actionLayout.addWidget(self.buy_replace) - - if self.cp.captured and self.ground_object.purchasable: - self.mainLayout.addLayout(self.actionLayout) - except Exception as e: - logging.exception(e) - self.update_total_value() - - def update_total_value(self): - if not self.ground_object.purchasable: - return - self.total_value = self.ground_object.value - if self.sell_all_button is not None: - self.sell_all_button.setText("Disband (+$" + str(self.total_value) + "M)") - - def repair_unit(self, unit, price): - if self.game.blue.budget > price: - self.game.blue.budget -= price - unit.alive = True - GameUpdateSignal.get_instance().updateGame(self.game) - - # Remove destroyed units in the vicinity - destroyed_units = self.game.get_destroyed_units() - for d in destroyed_units: - p = Point(d["x"], d["z"], self.game.theater.terrain) - if p.distance_to_point(unit.position) < 15: - destroyed_units.remove(d) - logging.info("Removed destroyed units " + str(d)) - logging.info(f"Repaired unit: {unit.unit_name}") - - self.update_game() - - def rotate_tgo(self, heading: Heading) -> None: - self.ground_object.rotate(heading) - self.heading_image.set_heading(heading) - - def sell_all(self): - self.update_total_value() - self.game.blue.budget += self.total_value - self.ground_object.groups = [] - self.update_game() - - def buy_group(self) -> None: - self.subwindow = QGroundObjectBuyMenu( - self, self.ground_object, self.game, self.total_value - ) - if self.subwindow.exec_(): - self.update_game() - - def update_game(self) -> None: - events = GameUpdateEvents() - events.update_tgo(self.ground_object) - self.game.theater.iads_network.update_tgo(self.ground_object, events) - if any( - package.target == self.ground_object - for package in self.game.ato_for(player=False).packages - ): - # Replan if the tgo was a target of the redfor - self.game.initialize_turn(events, for_red=True, for_blue=False) - EventStream.put_nowait(events) - GameUpdateSignal.get_instance().updateGame(self.game) - # Refresh the dialog - self.do_refresh_layout() diff --git a/qt_ui/windows/groundobject/QGroundObjectReplacementMenu.py b/qt_ui/windows/groundobject/QGroundObjectReplacementMenu.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/qt_ui/windows/infos/QInfoItem.py b/qt_ui/windows/infos/QInfoItem.py deleted file mode 100644 index 4c1c6a8a4..000000000 --- a/qt_ui/windows/infos/QInfoItem.py +++ /dev/null @@ -1,11 +0,0 @@ -from PySide6.QtGui import QStandardItem - -from game.infos.information import Information - - -class QInfoItem(QStandardItem): - def __init__(self, info: Information): - super(QInfoItem, self).__init__() - self.info = info - self.setText(str(info)) - self.setEditable(False) diff --git a/qt_ui/windows/infos/QInfoList.py b/qt_ui/windows/infos/QInfoList.py deleted file mode 100644 index ea5fb6cf3..000000000 --- a/qt_ui/windows/infos/QInfoList.py +++ /dev/null @@ -1,36 +0,0 @@ -from PySide6.QtCore import QItemSelectionModel, QPoint -from PySide6.QtGui import QStandardItemModel -from PySide6.QtWidgets import QListView - -from game import Game, game -from qt_ui.windows.infos.QInfoItem import QInfoItem - - -class QInfoList(QListView): - def __init__(self, game: Game): - super(QInfoList, self).__init__() - self.model = QStandardItemModel(self) - self.setModel(self.model) - self.game = game - self.update_list() - - self.selectionModel().setCurrentIndex( - self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select - ) - self.selectionModel().selectionChanged.connect(self.on_selected_info_changed) - - def on_selected_info_changed(self): - index = self.selectionModel().currentIndex().row() - - def update_list(self): - self.model.clear() - if self.game is not None: - for i, info in enumerate(reversed(self.game.informations)): - self.model.appendRow(QInfoItem(info)) - self.selectionModel().setCurrentIndex( - self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select - ) - - def setGame(self, game): - self.game = game - self.update_list() diff --git a/qt_ui/windows/infos/QInfoPanel.py b/qt_ui/windows/infos/QInfoPanel.py deleted file mode 100644 index 5c2cb6c23..000000000 --- a/qt_ui/windows/infos/QInfoPanel.py +++ /dev/null @@ -1,25 +0,0 @@ -from PySide6.QtWidgets import QFrame, QVBoxLayout, QLabel, QGroupBox - -from game import Game -from qt_ui.windows.infos.QInfoList import QInfoList - - -class QInfoPanel(QGroupBox): - def __init__(self, game: Game): - super(QInfoPanel, self).__init__("Info Panel") - self.informations_list = QInfoList(game) - self.init_ui() - - def setGame(self, game): - self.game = game - self.informations_list.setGame(game) - - def update(self): - self.informations_list.update_list() - - def init_ui(self): - layout = QVBoxLayout() - layout.addWidget(self.informations_list) - layout.setSpacing(0) - layout.setContentsMargins(0, 20, 0, 0) - self.setLayout(layout) diff --git a/qt_ui/windows/infos/QInfoWidget.py b/qt_ui/windows/infos/QInfoWidget.py deleted file mode 100644 index e55187628..000000000 --- a/qt_ui/windows/infos/QInfoWidget.py +++ /dev/null @@ -1,18 +0,0 @@ -from PySide6.QtWidgets import QFrame, QLabel, QGridLayout - -from game.infos.information import Information - - -class QInfoWidget(QFrame): - def __init__(self, info: Information): - super(QInfoWidget, self).__init__() - self.info = info - self.titleLabel = QLabel("" + info.title + "") - self.textLabel = QLabel(info.text) - self.init_ui() - - def init_ui(self): - layout = QGridLayout() - layout.addWidget(self.titleLabel, 0, 0) - layout.addWidget(self.textLabel, 1, 0) - self.setLayout(layout) diff --git a/qt_ui/windows/intel.py b/qt_ui/windows/intel.py deleted file mode 100644 index 866c6eef1..000000000 --- a/qt_ui/windows/intel.py +++ /dev/null @@ -1,184 +0,0 @@ -import itertools -from typing import Optional - -from PySide6.QtWidgets import ( - QCheckBox, - QDialog, - QFrame, - QGridLayout, - QLabel, - QLayout, - QScrollArea, - QSizePolicy, - QSpacerItem, - QTabWidget, - QVBoxLayout, - QWidget, -) - -from game.game import Game -from qt_ui.uiconstants import ICONS -from qt_ui.windows.finances.QFinancesMenu import FinancesLayout - - -class ScrollingFrame(QFrame): - def __init__(self) -> None: - super().__init__() - - widget = QWidget() - scroll_area = QScrollArea() - scroll_area.setWidgetResizable(True) - scroll_area.setWidget(widget) - - self.scrolling_layout = QVBoxLayout() - widget.setLayout(self.scrolling_layout) - - self.setLayout(QVBoxLayout()) - self.layout().addWidget(scroll_area) - - def addWidget(self, widget: QWidget, *args, **kwargs) -> None: - self.scrolling_layout.addWidget(widget, *args, **kwargs) - - def addLayout(self, layout: QLayout, *args, **kwargs) -> None: - self.scrolling_layout.addLayout(layout, *args, **kwargs) - - -class EconomyIntelTab(ScrollingFrame): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - self.addLayout(FinancesLayout(game, player=player)) - - -class IntelTableLayout(QGridLayout): - def __init__(self) -> None: - super().__init__() - self.row = itertools.count(0) - - def add_header(self, text: str) -> None: - self.addWidget(QLabel(f"{text}"), next(self.row), 0) - - def add_spacer(self) -> None: - self.addItem( - QSpacerItem(0, 0, QSizePolicy.Preferred, QSizePolicy.Expanding), - next(self.row), - 0, - ) - - def add_row(self, text: str, count: Optional[int] = None) -> None: - row = next(self.row) - self.addWidget(QLabel(text), row, 0) - if count is not None: # optional count for blank rows - self.addWidget(QLabel(str(count)), row, 1) - - -class AircraftIntelLayout(IntelTableLayout): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - - total = 0 - for control_point in game.theater.control_points_for(player): - allocation = control_point.allocated_aircraft() - base_total = allocation.total_present - total += base_total - if not base_total: - continue - - self.add_header(f"{control_point.name} ({base_total})") - for airframe in sorted(allocation.present, key=lambda k: k.display_name): - count = allocation.present[airframe] - if not count: - continue - self.add_row(f" {airframe.display_name}", count) - self.add_row("") - - self.add_row("Total", total) - self.add_spacer() - - -class AircraftIntelTab(ScrollingFrame): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - self.addLayout(AircraftIntelLayout(game, player=player)) - - -class ArmyIntelLayout(IntelTableLayout): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - - total = 0 - for control_point in game.theater.control_points_for(player): - base = control_point.base - total += base.total_armor - if not base.total_armor: - continue - - self.add_header(f"{control_point.name} ({base.total_armor})") - for vehicle in sorted(base.armor, key=lambda k: k.display_name): - count = base.armor[vehicle] - if not count: - continue - self.add_row(f" {vehicle.display_name}", count) - self.add_row("") - - self.add_row("Total", total) - self.add_spacer() - - -class ArmyIntelTab(ScrollingFrame): - def __init__(self, game: Game, player: bool) -> None: - super().__init__() - self.addLayout(ArmyIntelLayout(game, player=player)) - - -class IntelTabs(QTabWidget): - def __init__(self, game: Game, player: bool): - super().__init__() - - self.addTab(EconomyIntelTab(game, player), "Economy") - self.addTab(AircraftIntelTab(game, player), "Air forces") - self.addTab(ArmyIntelTab(game, player), "Ground forces") - - -class IntelWindow(QDialog): - def __init__(self, game: Game): - super().__init__() - - self.game = game - self.player = True - self.setModal(True) - self.setWindowTitle("Intelligence") - self.setWindowIcon(ICONS["Statistics"]) - self.setMinimumSize(600, 500) - self.selected_intel_tab = 0 - - layout = QVBoxLayout() - self.setLayout(layout) - self.refresh_layout() - - def on_faction_changed(self) -> None: - self.player = not self.player - self.refresh_layout() - - def refresh_layout(self) -> None: - # Clear the existing layout - if self.layout(): - idx = 0 - while child := self.layout().itemAt(idx): - self.layout().removeItem(child) - - # Add the new layout - own_faction = QCheckBox("Enemy Info") - own_faction.setChecked(not self.player) - own_faction.stateChanged.connect(self.on_faction_changed) - - intel_tabs = IntelTabs(self.game, self.player) - intel_tabs.currentChanged.connect(self.on_tab_changed) - - if self.selected_intel_tab: - intel_tabs.setCurrentIndex(self.selected_intel_tab) - - self.layout().addWidget(own_faction) - self.layout().addWidget(intel_tabs, stretch=1) - - def on_tab_changed(self, idx: int) -> None: - self.selected_intel_tab = idx diff --git a/qt_ui/windows/logs/QLogsWindow.py b/qt_ui/windows/logs/QLogsWindow.py deleted file mode 100644 index baebbee95..000000000 --- a/qt_ui/windows/logs/QLogsWindow.py +++ /dev/null @@ -1,80 +0,0 @@ -import typing - -from PySide6.QtCore import Signal -from PySide6.QtGui import QTextCursor, QIcon -from PySide6.QtWidgets import ( - QDialog, - QPlainTextEdit, - QVBoxLayout, - QPushButton, -) - -from qt_ui.logging_handler import HookableInMemoryHandler - - -class QLogsWindow(QDialog): - appendLogSignal = Signal(str) - - vbox: QVBoxLayout - textbox: QPlainTextEdit - clear_button: QPushButton - _logging_handler: typing.Optional[HookableInMemoryHandler] - - def __init__(self): - super().__init__() - - self.setWindowTitle("Logs") - self.setMinimumSize(400, 100) - self.resize(1000, 450) - self.setWindowIcon(QIcon("./resources/icon.png")) - - self.vbox = QVBoxLayout() - self.setLayout(self.vbox) - - self.textbox = QPlainTextEdit(self) - self.textbox.setReadOnly(True) - self.textbox.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap) - self.textbox.move(10, 10) - self.textbox.resize(1000, 450) - self.textbox.setStyleSheet( - "font-family: 'Courier New', monospace; background: #1D2731;" - ) - self.vbox.addWidget(self.textbox) - - self.clear_button = QPushButton(self) - self.clear_button.setText("CLEAR") - self.clear_button.setProperty("style", "btn-primary") - self.clear_button.clicked.connect(self.clearLogs) - self.vbox.addWidget(self.clear_button) - - self.appendLogSignal.connect(self.appendLog) - - try: - # This assumes that there's never more than one in memory handler. We don't - # configure more than one by default, but logging is customizable with - # resources/logging.yaml. If someone adds a second in-memory handler, only - # the first one (in arbitrary order) will be shown. - self._logging_handler = next( - HookableInMemoryHandler.iter_registered_handlers() - ) - except StopIteration: - self._logging_handler = None - - if self._logging_handler is not None: - self.textbox.setPlainText(self._logging_handler.log) - self.textbox.moveCursor(QTextCursor.End) - # The Handler might be called from a different thread, - # so use signal/slot to properly handle the event in the main thread. - # https://github.com/dcs-liberation/dcs_liberation/issues/1493 - self._logging_handler.setHook(self.appendLogSignal.emit) - else: - self.textbox.setPlainText("WARNING: logging not initialized!") - - def clearLogs(self) -> None: - if self._logging_handler is not None: - self._logging_handler.clearLog() - self.textbox.setPlainText("") - - def appendLog(self, msg: str): - self.textbox.appendPlainText(msg) - self.textbox.moveCursor(QTextCursor.End) diff --git a/qt_ui/windows/mission/QEditFlightDialog.py b/qt_ui/windows/mission/QEditFlightDialog.py deleted file mode 100644 index 935ac5ef4..000000000 --- a/qt_ui/windows/mission/QEditFlightDialog.py +++ /dev/null @@ -1,44 +0,0 @@ -"""Dialog window for editing flights.""" -from PySide6.QtWidgets import ( - QDialog, - QVBoxLayout, -) - -from game.ato.flight import Flight -from game.server import EventStream -from game.sim import GameUpdateEvents -from qt_ui.models import GameModel, PackageModel -from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.windows.mission.flight.QFlightPlanner import QFlightPlanner - - -class QEditFlightDialog(QDialog): - """Dialog window for editing flight plans and loadouts.""" - - def __init__( - self, - game_model: GameModel, - package_model: PackageModel, - flight: Flight, - parent=None, - ) -> None: - super().__init__(parent=parent) - - self.game_model = game_model - self.flight = flight - - self.setWindowTitle("Edit flight") - self.setWindowIcon(EVENT_ICONS["strike"]) - self.setModal(True) - - layout = QVBoxLayout() - - self.flight_planner = QFlightPlanner(package_model, flight, game_model.game) - layout.addWidget(self.flight_planner) - - self.setLayout(layout) - self.finished.connect(self.on_close) - - def on_close(self, _result) -> None: - EventStream.put_nowait(GameUpdateEvents().update_flight(self.flight)) - self.game_model.ato_model.client_slots_changed.emit() diff --git a/qt_ui/windows/mission/QFlightItem.py b/qt_ui/windows/mission/QFlightItem.py deleted file mode 100644 index ebdbf0c97..000000000 --- a/qt_ui/windows/mission/QFlightItem.py +++ /dev/null @@ -1,19 +0,0 @@ -from PySide6.QtGui import QIcon, QStandardItem - -from game.ato.flight import Flight -from game.ato.package import Package -from qt_ui.uiconstants import AIRCRAFT_ICONS - - -# TODO: Replace with QFlightList. -class QFlightItem(QStandardItem): - def __init__(self, package: Package, flight: Flight): - super(QFlightItem, self).__init__() - self.package = package - self.flight = flight - - if self.flight.unit_type.dcs_id in AIRCRAFT_ICONS: - icon = QIcon((AIRCRAFT_ICONS[self.flight.unit_type.dcs_id])) - self.setIcon(icon) - self.setEditable(False) - self.setText(f"{flight} at {flight.flight_plan.startup_time()}") diff --git a/qt_ui/windows/mission/QPackageDialog.py b/qt_ui/windows/mission/QPackageDialog.py deleted file mode 100644 index dfb3dae5c..000000000 --- a/qt_ui/windows/mission/QPackageDialog.py +++ /dev/null @@ -1,294 +0,0 @@ -"""Dialogs for creating and editing ATO packages.""" -import logging -from typing import Optional - -from PySide6.QtCore import QItemSelection, QTime, Qt, Signal -from PySide6.QtWidgets import ( - QCheckBox, - QDialog, - QHBoxLayout, - QLabel, - QMessageBox, - QPushButton, - QTimeEdit, - QVBoxLayout, -) - -from game.ato.flight import Flight -from game.ato.flightplans.planningerror import PlanningError -from game.ato.package import Package -from game.game import Game -from game.server import EventStream -from game.sim import GameUpdateEvents -from game.theater.missiontarget import MissionTarget -from qt_ui.models import AtoModel, GameModel, PackageModel -from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.widgets.ato import QFlightList -from qt_ui.windows.mission.flight.QFlightCreator import QFlightCreator - - -class QPackageDialog(QDialog): - """Base package management dialog. - - The dialogs for creating a new package and editing an existing dialog are - very similar, and this implements the shared behavior. - """ - - #: Emitted when a change is made to the package. - package_changed = Signal() - - def __init__(self, game_model: GameModel, model: PackageModel, parent=None) -> None: - super().__init__(parent) - self.game_model = game_model - self.package_model = model - self.add_flight_dialog: Optional[QFlightCreator] = None - - self.setMinimumSize(1000, 440) - self.setWindowTitle( - f"Mission Package: {self.package_model.mission_target.name}" - ) - self.setWindowIcon(EVENT_ICONS["strike"]) - - self.layout = QVBoxLayout() - - self.summary_row = QHBoxLayout() - self.layout.addLayout(self.summary_row) - - self.package_type_column = QHBoxLayout() - self.summary_row.addLayout(self.package_type_column) - - self.package_type_label = QLabel("Package Type:") - self.package_type_text = QLabel(self.package_model.description) - # noinspection PyUnresolvedReferences - self.package_changed.connect( - lambda: self.package_type_text.setText(self.package_model.description) - ) - self.package_type_column.addWidget(self.package_type_label) - self.package_type_column.addWidget(self.package_type_text) - - self.summary_row.addStretch(1) - - self.tot_column = QHBoxLayout() - self.summary_row.addLayout(self.tot_column) - - self.tot_label = QLabel("Time Over Target:") - self.tot_column.addWidget(self.tot_label) - - self.tot_spinner = QTimeEdit(self.tot_qtime()) - self.tot_spinner.setMinimumTime(QTime(0, 0)) - self.tot_spinner.setDisplayFormat("hh:mm:ss") - self.tot_spinner.timeChanged.connect(self.save_tot) - self.tot_spinner.setToolTip("Package TOT relative to mission TOT") - self.tot_spinner.setEnabled( - not self.package_model.package.auto_asap - and self.package_model.package.all_flights_waiting_for_start() - ) - self.tot_column.addWidget(self.tot_spinner) - - self.auto_asap = QCheckBox("ASAP") - self.auto_asap.setToolTip( - "Sets the package TOT to the earliest time that all flights can " - "arrive at the target." - ) - self.auto_asap.setChecked(self.package_model.package.auto_asap) - self.auto_asap.setEnabled( - self.package_model.package.all_flights_waiting_for_start() - ) - self.auto_asap.toggled.connect(self.set_asap) - self.tot_column.addWidget(self.auto_asap) - - self.tot_help_label = QLabel( - 'Help' - ) - self.tot_help_label.setAlignment(Qt.AlignCenter) - self.tot_help_label.setOpenExternalLinks(True) - self.tot_column.addWidget(self.tot_help_label) - - self.package_view = QFlightList(self.game_model, self.package_model) - self.package_view.selectionModel().selectionChanged.connect( - self.on_selection_changed - ) - self.layout.addWidget(self.package_view) - - self.button_layout = QHBoxLayout() - self.layout.addLayout(self.button_layout) - - self.add_flight_button = QPushButton("Add Flight") - self.add_flight_button.clicked.connect(self.on_add_flight) - self.add_flight_button.setEnabled( - self.package_model.package.all_flights_waiting_for_start() - ) - self.button_layout.addWidget(self.add_flight_button) - - self.delete_flight_button = QPushButton("Delete Selected") - self.delete_flight_button.setProperty("style", "btn-danger") - self.delete_flight_button.clicked.connect(self.on_delete_flight) - self.delete_flight_button.setEnabled(model.rowCount() > 0) - self.button_layout.addWidget(self.delete_flight_button) - - self.package_model.tot_changed.connect(self.update_tot) - - self.button_layout.addStretch() - - self.setLayout(self.layout) - - self.accepted.connect(self.on_save) - self.finished.connect(self.on_close) - self.rejected.connect(self.on_cancel) - - @property - def game(self) -> Game: - return self.game_model.game - - def tot_qtime(self) -> QTime: - tot = self.package_model.package.time_over_target - return QTime(tot.hour, tot.minute, tot.second) - - def on_cancel(self) -> None: - pass - - def on_close(self, _result) -> None: - EventStream.put_nowait( - GameUpdateEvents().update_flights_in_package(self.package_model.package) - ) - - def on_save(self) -> None: - self.save_tot() - - def save_tot(self) -> None: - # TODO: This is going to break horribly around midnight. - time = self.tot_spinner.time() - tot = self.package_model.set_tot( - self.package_model.package.time_over_target.replace( - hour=time.hour(), minute=time.minute(), second=time.second() - ) - ) - self.tot_spinner.setTime(self.tot_qtime()) - - def set_asap(self, checked: bool) -> None: - self.package_model.set_asap(checked) - self.tot_spinner.setEnabled(not self.package_model.package.auto_asap) - self.update_tot() - - def update_tot(self) -> None: - self.tot_spinner.setTime(self.tot_qtime()) - - def on_selection_changed( - self, selected: QItemSelection, _deselected: QItemSelection - ) -> None: - """Updates the state of the delete button.""" - self.delete_flight_button.setEnabled(not selected.empty()) - - def on_add_flight(self) -> None: - """Opens the new flight dialog.""" - self.add_flight_dialog = QFlightCreator( - self.game, self.package_model.package, parent=self.window() - ) - self.add_flight_dialog.created.connect(self.add_flight) - self.add_flight_dialog.show() - - def add_flight(self, flight: Flight) -> None: - """Adds the new flight to the package.""" - self.package_model.add_flight(flight) - try: - flight.recreate_flight_plan() - self.package_model.update_tot() - EventStream.put_nowait(GameUpdateEvents().new_flight(flight)) - except PlanningError as ex: - self.package_model.delete_flight(flight) - logging.exception("Could not create flight") - QMessageBox.critical( - self, "Could not create flight", str(ex), QMessageBox.Ok - ) - # noinspection PyUnresolvedReferences - self.package_changed.emit() - - def on_delete_flight(self) -> None: - """Removes the selected flight from the package.""" - flight = self.package_view.selected_item - if flight is None: - logging.error(f"Cannot delete flight when no flight is selected.") - return - self.package_model.cancel_or_abort_flight(flight) - # noinspection PyUnresolvedReferences - self.package_changed.emit() - - -class QNewPackageDialog(QPackageDialog): - """Dialog window for creating a new package. - - New packages do not affect the ATO model until they are saved. - """ - - def __init__( - self, game_model: GameModel, model: AtoModel, target: MissionTarget, parent=None - ) -> None: - super().__init__( - game_model, - PackageModel( - Package(target, game_model.game.db.flights, auto_asap=True), game_model - ), - parent=parent, - ) - self.ato_model = model - - # In the *new* package dialog, a package has been created and may have aircraft - # assigned to it, but it is not a part of the ATO until the user saves it. - # - # Other actions (modifying settings, closing some other dialogs like the base - # menu) can cause a Game update which will forcibly close this window without - # either accepting or rejecting it, so we neither save the package nor release - # any allocated units. - # - # While it would be preferable to be able to update this dialog as needed in the - # event of game updates, the quick fix is to just not allow interaction with - # other UI elements until the new package has either been finalized or canceled. - self.setModal(True) - - self.save_button = QPushButton("Save") - self.save_button.setProperty("style", "start-button") - self.save_button.clicked.connect(self.accept) - self.button_layout.addWidget(self.save_button) - - def on_save(self) -> None: - """Saves the created package. - - Empty packages may be created. They can be modified later, and will have - no effect if empty when the mission is generated. - """ - super().on_save() - self.ato_model.add_package(self.package_model.package) - - def on_cancel(self) -> None: - super().on_cancel() - for flight in list(self.package_model.package.flights): - self.package_model.cancel_or_abort_flight(flight) - - -class QEditPackageDialog(QPackageDialog): - """Dialog window for editing an existing package. - - Changes to existing packages occur immediately. - """ - - def __init__( - self, game_model: GameModel, model: AtoModel, package: PackageModel - ) -> None: - super().__init__(game_model, package) - self.ato_model = model - - self.delete_button = QPushButton("Delete package") - self.delete_button.setProperty("style", "btn-danger") - self.delete_button.clicked.connect(self.on_delete) - self.button_layout.addWidget(self.delete_button) - - self.done_button = QPushButton("Done") - self.done_button.setProperty("style", "start-button") - self.done_button.clicked.connect(self.accept) - self.button_layout.addWidget(self.done_button) - - def on_delete(self) -> None: - """Removes the viewed package from the ATO.""" - # The ATO model returns inventory for us when deleting a package. - self.ato_model.cancel_or_abort_package(self.package_model.package) - self.close() diff --git a/qt_ui/windows/mission/QPlannedFlightsView.py b/qt_ui/windows/mission/QPlannedFlightsView.py deleted file mode 100644 index 2839d14b7..000000000 --- a/qt_ui/windows/mission/QPlannedFlightsView.py +++ /dev/null @@ -1,54 +0,0 @@ -from datetime import datetime - -from PySide6.QtCore import QItemSelectionModel, QSize -from PySide6.QtGui import QStandardItemModel -from PySide6.QtWidgets import QAbstractItemView, QListView - -from game.theater.controlpoint import ControlPoint -from qt_ui.models import GameModel -from qt_ui.windows.mission.QFlightItem import QFlightItem - - -class QPlannedFlightsView(QListView): - def __init__(self, game_model: GameModel, cp: ControlPoint) -> None: - super(QPlannedFlightsView, self).__init__() - self.game_model = game_model - self.cp = cp - self.model = QStandardItemModel(self) - self.setModel(self.model) - self.flight_items = [] - self.setIconSize(QSize(91, 24)) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - self.set_flight_planner() - - def setup_content(self): - self.flight_items = [] - for package in self.game_model.ato_model.packages: - for flight in package.flights: - if flight.departure == self.cp: - item = QFlightItem(package.package, flight) - self.flight_items.append(item) - - self.flight_items.sort(key=self.mission_start_for_flight) - for item in self.flight_items: - self.model.appendRow(item) - self.set_selected_flight(0) - - def set_selected_flight(self, row): - self.selectionModel().clearSelection() - index = self.model.index(row, 0) - if not index.isValid(): - index = self.model.index(0, 0) - self.selectionModel().setCurrentIndex(index, QItemSelectionModel.Select) - self.repaint() - - def clear_layout(self): - self.model.removeRows(0, self.model.rowCount()) - - def set_flight_planner(self) -> None: - self.clear_layout() - self.setup_content() - - @staticmethod - def mission_start_for_flight(flight_item: QFlightItem) -> datetime: - return flight_item.flight.flight_plan.startup_time() diff --git a/qt_ui/windows/mission/flight/QF14FlightComputerEditor.py b/qt_ui/windows/mission/flight/QF14FlightComputerEditor.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/qt_ui/windows/mission/flight/QFlightAircraftEditor.py b/qt_ui/windows/mission/flight/QFlightAircraftEditor.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/qt_ui/windows/mission/flight/QFlightCreator.py b/qt_ui/windows/mission/flight/QFlightCreator.py deleted file mode 100644 index 641a65f85..000000000 --- a/qt_ui/windows/mission/flight/QFlightCreator.py +++ /dev/null @@ -1,257 +0,0 @@ -from typing import Optional, Type - -from PySide6.QtCore import Qt, Signal -from PySide6.QtWidgets import ( - QComboBox, - QDialog, - QHBoxLayout, - QLabel, - QLineEdit, - QMessageBox, - QPushButton, - QVBoxLayout, -) -from dcs.unittype import FlyingType - -from game import Game -from game.ato.flight import Flight -from game.ato.flightroster import FlightRoster -from game.ato.package import Package -from game.ato.starttype import StartType -from game.squadrons.squadron import Squadron -from game.theater import ControlPoint, OffMapSpawn -from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.widgets.QFlightSizeSpinner import QFlightSizeSpinner -from qt_ui.widgets.QLabeledWidget import QLabeledWidget -from qt_ui.widgets.combos.QAircraftTypeSelector import QAircraftTypeSelector -from qt_ui.widgets.combos.QArrivalAirfieldSelector import QArrivalAirfieldSelector -from qt_ui.widgets.combos.QFlightTypeComboBox import QFlightTypeComboBox -from qt_ui.windows.mission.flight.SquadronSelector import SquadronSelector -from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import FlightRosterEditor - - -class QFlightCreator(QDialog): - created = Signal(Flight) - - def __init__(self, game: Game, package: Package, parent=None) -> None: - super().__init__(parent=parent) - self.setMinimumWidth(400) - - self.game = game - self.package = package - self.custom_name_text = None - self.country = self.game.blue.country_name - - # Make dialog modal to prevent background windows to close unexpectedly. - self.setModal(True) - - self.setWindowTitle("Create flight") - self.setWindowIcon(EVENT_ICONS["strike"]) - - layout = QVBoxLayout() - - self.task_selector = QFlightTypeComboBox( - self.game.theater, package.target, self.game.lua_plugin_manager - ) - self.task_selector.setCurrentIndex(0) - self.task_selector.currentIndexChanged.connect(self.on_task_changed) - layout.addLayout(QLabeledWidget("Task:", self.task_selector)) - - self.aircraft_selector = QAircraftTypeSelector( - self.game.blue.air_wing.best_available_aircrafts_for( - self.task_selector.currentData() - ) - ) - self.aircraft_selector.setCurrentIndex(0) - self.aircraft_selector.currentIndexChanged.connect(self.on_aircraft_changed) - layout.addLayout(QLabeledWidget("Aircraft:", self.aircraft_selector)) - - self.squadron_selector = SquadronSelector( - self.game.air_wing_for(player=True), - self.task_selector.currentData(), - self.aircraft_selector.currentData(), - ) - self.squadron_selector.setCurrentIndex(0) - layout.addLayout(QLabeledWidget("Squadron:", self.squadron_selector)) - - self.divert = QArrivalAirfieldSelector( - [cp for cp in game.theater.controlpoints if cp.captured], - self.aircraft_selector.currentData(), - "None", - ) - layout.addLayout(QLabeledWidget("Divert:", self.divert)) - - self.flight_size_spinner = QFlightSizeSpinner() - self.update_max_size(self.squadron_selector.aircraft_available) - layout.addLayout(QLabeledWidget("Size:", self.flight_size_spinner)) - - squadron = self.squadron_selector.currentData() - if squadron is None: - roster = None - else: - roster = FlightRoster( - squadron, - initial_size=self.flight_size_spinner.value(), - ) - self.roster_editor = FlightRosterEditor(squadron, roster) - self.flight_size_spinner.valueChanged.connect(self.roster_editor.resize) - self.squadron_selector.currentIndexChanged.connect(self.on_squadron_changed) - roster_layout = QHBoxLayout() - layout.addLayout(roster_layout) - roster_layout.addWidget(QLabel("Assigned pilots:")) - roster_layout.addLayout(self.roster_editor) - - # When an off-map spawn overrides the start type to in-flight, we save - # the selected type into this value. If a non-off-map spawn is selected - # we restore the previous choice. - self.restore_start_type = self.game.settings.default_start_type - self.start_type = QComboBox() - for start_type in StartType: - self.start_type.addItem(start_type.value, start_type) - self.start_type.setCurrentText(self.game.settings.default_start_type.value) - layout.addLayout( - QLabeledWidget( - "Start type:", - self.start_type, - tooltip="Selects the start type for this flight.", - ) - ) - if squadron is not None and isinstance(squadron.location, OffMapSpawn): - self.start_type.setCurrentText(StartType.IN_FLIGHT.value) - self.start_type.setEnabled(False) - layout.addWidget( - QLabel( - "Any option other than Cold will make this flight " - + "non-targetable
    by OCA/Aircraft missions. This will affect " - + "game balance." - ) - ) - - self.custom_name = QLineEdit() - self.custom_name.textChanged.connect(self.set_custom_name_text) - layout.addLayout( - QLabeledWidget("Custom Flight Name (Optional)", self.custom_name) - ) - - layout.addStretch() - - self.create_button = QPushButton("Create") - self.create_button.clicked.connect(self.create_flight) - layout.addWidget(self.create_button, alignment=Qt.AlignRight) - - self.setLayout(layout) - - def reject(self) -> None: - super().reject() - # Clear the roster to return pilots to the pool. - self.roster_editor.replace(None, None) - - def set_custom_name_text(self, text: str): - self.custom_name_text = text - - def verify_form(self) -> Optional[str]: - aircraft: Optional[Type[FlyingType]] = self.aircraft_selector.currentData() - squadron: Optional[Squadron] = self.squadron_selector.currentData() - divert: Optional[ControlPoint] = self.divert.currentData() - size: int = self.flight_size_spinner.value() - if aircraft is None: - return "You must select an aircraft type." - if squadron is None: - return "You must select a squadron." - if divert is not None and not divert.captured: - return f"{divert.name} is not owned by your coalition." - available = squadron.untasked_aircraft - if not available: - return f"{squadron} has no aircraft available." - if size > available: - return f"{squadron} has only {available} aircraft available." - if size <= 0: - return f"Flight must have at least one aircraft." - if self.custom_name_text and "|" in self.custom_name_text: - return f"Cannot include | in flight name" - return None - - def create_flight(self) -> None: - error = self.verify_form() - if error is not None: - QMessageBox.critical(self, "Could not create flight", error, QMessageBox.Ok) - return - - task = self.task_selector.currentData() - squadron = self.squadron_selector.currentData() - divert = self.divert.currentData() - roster = self.roster_editor.roster - - flight = Flight( - self.package, - self.country, - squadron, - # A bit of a hack to work around the old API. Not actually relevant because - # the roster is passed explicitly. Needs a refactor. - roster.max_size, - task, - self.start_type.currentData(), - divert, - custom_name=self.custom_name_text, - roster=roster, - ) - - for member in flight.iter_members(): - if member.is_player: - member.assign_tgp_laser_code( - self.game.laser_code_registry.alloc_laser_code() - ) - - # noinspection PyUnresolvedReferences - self.created.emit(flight) - self.accept() - - def on_aircraft_changed(self, index: int) -> None: - new_aircraft = self.aircraft_selector.itemData(index) - self.squadron_selector.update_items( - self.task_selector.currentData(), new_aircraft - ) - self.divert.change_aircraft(new_aircraft) - - def on_departure_changed(self, departure: ControlPoint) -> None: - if isinstance(departure, OffMapSpawn): - previous_type = self.start_type.currentData() - if previous_type != StartType.IN_FLIGHT: - self.restore_start_type = previous_type - self.start_type.setCurrentText(StartType.IN_FLIGHT.value) - self.start_type.setEnabled(False) - else: - self.start_type.setEnabled(True) - if self.restore_start_type is not None: - self.start_type.setCurrentText(self.restore_start_type.value) - self.restore_start_type = None - - def on_task_changed(self, index: int) -> None: - task = self.task_selector.itemData(index) - self.aircraft_selector.update_items( - self.game.blue.air_wing.best_available_aircrafts_for(task) - ) - self.squadron_selector.update_items(task, self.aircraft_selector.currentData()) - - def on_squadron_changed(self, index: int) -> None: - squadron: Optional[Squadron] = self.squadron_selector.itemData(index) - self.update_max_size(self.squadron_selector.aircraft_available) - # Clear the roster first so that we return the pilots to the pool. This way if - # we end up repopulating from the same squadron we'll get the same pilots back. - self.roster_editor.replace(None, None) - if squadron is not None: - self.roster_editor.replace( - squadron, FlightRoster(squadron, self.flight_size_spinner.value()) - ) - self.on_departure_changed(squadron.location) - - def update_max_size(self, available: int) -> None: - aircraft = self.aircraft_selector.currentData() - if aircraft is None: - self.flight_size_spinner.setMaximum(0) - return - - self.flight_size_spinner.setMaximum(min(available, aircraft.max_group_size)) - - default_size = max(2, available, aircraft.max_group_size) - self.flight_size_spinner.setValue(default_size) diff --git a/qt_ui/windows/mission/flight/QFlightPlanner.py b/qt_ui/windows/mission/flight/QFlightPlanner.py deleted file mode 100644 index db4d5ce91..000000000 --- a/qt_ui/windows/mission/flight/QFlightPlanner.py +++ /dev/null @@ -1,29 +0,0 @@ -from PySide6.QtWidgets import QTabWidget - -from game import Game -from game.ato.flight import Flight -from qt_ui.models import PackageModel -from qt_ui.windows.mission.flight.payload.QFlightPayloadTab import QFlightPayloadTab -from qt_ui.windows.mission.flight.settings.QGeneralFlightSettingsTab import ( - QGeneralFlightSettingsTab, -) -from qt_ui.windows.mission.flight.waypoints.QFlightWaypointTab import QFlightWaypointTab - - -class QFlightPlanner(QTabWidget): - def __init__(self, package_model: PackageModel, flight: Flight, game: Game): - super().__init__() - - self.general_settings_tab = QGeneralFlightSettingsTab( - game, package_model, flight - ) - self.payload_tab = QFlightPayloadTab(flight, game) - self.general_settings_tab.flight_size_changed.connect( - self.payload_tab.resize_for_flight - ) - self.waypoint_tab = QFlightWaypointTab(game, package_model.package, flight) - self.waypoint_tab.loadout_changed.connect(self.payload_tab.reload_from_flight) - self.addTab(self.general_settings_tab, "General Flight settings") - self.addTab(self.payload_tab, "Payload") - self.addTab(self.waypoint_tab, "Waypoints") - self.setCurrentIndex(0) diff --git a/qt_ui/windows/mission/flight/SquadronSelector.py b/qt_ui/windows/mission/flight/SquadronSelector.py deleted file mode 100644 index 65969a186..000000000 --- a/qt_ui/windows/mission/flight/SquadronSelector.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Combo box for selecting squadrons.""" -from typing import Optional - -from PySide6.QtWidgets import QComboBox - -from game.ato.flighttype import FlightType -from game.dcs.aircrafttype import AircraftType -from game.squadrons.airwing import AirWing - - -class SquadronSelector(QComboBox): - """Combo box for selecting squadrons compatible with the given requirements.""" - - def __init__( - self, - air_wing: AirWing, - task: Optional[FlightType], - aircraft: Optional[AircraftType], - ) -> None: - super().__init__() - self.air_wing = air_wing - - self.model().sort(0) - self.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents) - self.update_items(task, aircraft) - - @property - def aircraft_available(self) -> int: - squadron = self.currentData() - if squadron is None: - return 0 - return squadron.untasked_aircraft - - def update_items( - self, task: Optional[FlightType], aircraft: Optional[AircraftType] - ) -> None: - current_squadron = self.currentData() - self.blockSignals(True) - try: - self.clear() - finally: - self.blockSignals(False) - if task is None: - self.addItem("No task selected", None) - return - if aircraft is None: - self.addItem("No aircraft selected", None) - return - - for squadron in self.air_wing.squadrons_for(aircraft): - if not squadron.capable_of(task): - continue - if not squadron.untasked_aircraft: - continue - if squadron.location.ferry_only: - continue - self.addItem(f"{squadron.location}: {squadron}", squadron) - - if self.count() == 0: - self.addItem("No capable aircraft available", None) - return - - if current_squadron is not None: - self.setCurrentText(f"{current_squadron.location}: {current_squadron}") diff --git a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py b/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py deleted file mode 100644 index 1cf22a5ed..000000000 --- a/qt_ui/windows/mission/flight/payload/QFlightPayloadTab.py +++ /dev/null @@ -1,200 +0,0 @@ -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QComboBox, - QFrame, - QLabel, - QVBoxLayout, - QScrollArea, - QWidget, - QSpinBox, - QCheckBox, -) - -from game import Game -from game.ato.flight import Flight -from game.ato.flightmember import FlightMember -from game.ato.loadouts import Loadout -from qt_ui.widgets.QLabeledWidget import QLabeledWidget -from .QLoadoutEditor import QLoadoutEditor -from .ownlasercodeinfo import OwnLaserCodeInfo -from .propertyeditor import PropertyEditor -from .weaponlasercodeselector import WeaponLaserCodeSelector - - -class DcsLoadoutSelector(QComboBox): - def __init__(self, flight: Flight, member: FlightMember) -> None: - super().__init__() - for loadout in Loadout.iter_for(flight): - self.addItem(loadout.name, loadout) - self.model().sort(0) - self.setDisabled(member.loadout.is_custom) - if member.loadout.is_custom: - self.setCurrentText(Loadout.default_for(flight).name) - else: - self.setCurrentText(member.loadout.name) - - -class FlightMemberSelector(QSpinBox): - def __init__(self, flight: Flight, parent: QWidget | None = None) -> None: - super().__init__(parent) - self.flight = flight - self.setMinimum(1) - self.setMaximum(flight.count) - - @property - def selected_member(self) -> FlightMember: - return self.flight.roster.members[self.value() - 1] - - -class QFlightPayloadTab(QFrame): - def __init__(self, flight: Flight, game: Game): - super(QFlightPayloadTab, self).__init__() - self.flight = flight - self.payload_editor = QLoadoutEditor( - flight, self.flight.roster.members[0], game - ) - self.payload_editor.toggled.connect(self.on_custom_toggled) - - layout = QVBoxLayout() - - self.member_selector = FlightMemberSelector(self.flight, self) - self.member_selector.valueChanged.connect(self.rebind_to_selected_member) - layout.addLayout(QLabeledWidget("Flight member:", self.member_selector)) - self.same_loadout_for_all_checkbox = QCheckBox( - "Use same loadout for all flight members" - ) - self.same_loadout_for_all_checkbox.setChecked( - self.flight.use_same_loadout_for_all_members - ) - self.same_loadout_for_all_checkbox.toggled.connect(self.on_same_loadout_toggled) - layout.addWidget(self.same_loadout_for_all_checkbox) - layout.addWidget( - QLabel( - "Warning: AI flights should use the same loadout for all members." - ) - ) - - scroll_content = QWidget() - scrolling_layout = QVBoxLayout() - scroll_content.setLayout(scrolling_layout) - - scroll = QScrollArea() - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - layout.addWidget(scroll) - - # Docs Link - docsText = QLabel( - 'How to create your own default loadout' - ) - docsText.setAlignment(Qt.AlignCenter) - docsText.setOpenExternalLinks(True) - - self.own_laser_code_info = OwnLaserCodeInfo( - game, self.member_selector.selected_member - ) - scrolling_layout.addLayout(self.own_laser_code_info) - - self.weapon_laser_code_selector = WeaponLaserCodeSelector( - game, self.member_selector.selected_member, self - ) - self.own_laser_code_info.assigned_laser_code_changed.connect( - self.weapon_laser_code_selector.rebuild - ) - scrolling_layout.addLayout( - QLabeledWidget( - "Preset laser code for weapons:", self.weapon_laser_code_selector - ) - ) - scrolling_layout.addWidget( - QLabel( - "Equipped weapons will be pre-configured to the selected laser code at " - "mission start." - ) - ) - - self.property_editor = PropertyEditor( - self.flight, self.member_selector.selected_member - ) - scrolling_layout.addLayout(self.property_editor) - self.loadout_selector = DcsLoadoutSelector( - flight, self.member_selector.selected_member - ) - self.loadout_selector.currentIndexChanged.connect(self.on_new_loadout) - scrolling_layout.addWidget(self.loadout_selector) - scrolling_layout.addWidget(self.payload_editor) - scrolling_layout.addWidget(docsText) - - self.setLayout(layout) - - def resize_for_flight(self) -> None: - self.member_selector.setMaximum(self.flight.count - 1) - - def reload_from_flight(self) -> None: - self.loadout_selector.setCurrentText( - self.member_selector.selected_member.loadout.name - ) - - def rebind_to_selected_member(self) -> None: - member = self.member_selector.selected_member - self.property_editor.set_flight_member(member) - self.loadout_selector.setCurrentText(member.loadout.name) - self.loadout_selector.setDisabled(member.loadout.is_custom) - self.payload_editor.set_flight_member(member) - self.weapon_laser_code_selector.set_flight_member(member) - self.own_laser_code_info.set_flight_member(member) - if self.member_selector.value() != 0: - self.loadout_selector.setDisabled( - self.flight.use_same_loadout_for_all_members - ) - self.payload_editor.setDisabled( - self.flight.use_same_loadout_for_all_members - ) - else: - self.loadout_selector.setEnabled(True) - self.payload_editor.setEnabled(True) - - def loadout_at(self, index: int) -> Loadout: - loadout = self.loadout_selector.itemData(index) - if loadout is None: - return Loadout.empty_loadout() - return loadout - - def current_loadout(self) -> Loadout: - loadout = self.loadout_selector.currentData() - if loadout is None: - return Loadout.empty_loadout() - return loadout - - def on_new_loadout(self, index: int) -> None: - loadout = self.loadout_at(index) - self.member_selector.selected_member.loadout = loadout - if self.flight.use_same_loadout_for_all_members: - self.flight.roster.use_same_loadout_for_all_members() - self.payload_editor.reset_pylons() - - def on_custom_toggled(self, use_custom: bool) -> None: - self.loadout_selector.setDisabled(use_custom) - member = self.member_selector.selected_member - member.use_custom_loadout = use_custom - if use_custom: - member.loadout = member.loadout.derive_custom("Custom") - else: - member.loadout = self.current_loadout() - self.payload_editor.reset_pylons() - - if self.flight.use_same_loadout_for_all_members: - self.flight.roster.use_same_loadout_for_all_members() - - def on_same_loadout_toggled(self, checked: bool) -> None: - self.flight.use_same_loadout_for_all_members = checked - if self.member_selector.value(): - self.loadout_selector.setDisabled(checked) - self.payload_editor.setDisabled(checked) - if checked: - self.flight.roster.use_same_loadout_for_all_members() - if self.member_selector.value(): - self.rebind_to_selected_member() - else: - self.flight.roster.use_distinct_loadouts_for_each_member() diff --git a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py b/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py deleted file mode 100644 index 5c74bebf1..000000000 --- a/qt_ui/windows/mission/flight/payload/QLoadoutEditor.py +++ /dev/null @@ -1,58 +0,0 @@ -from collections.abc import Iterator - -from PySide6.QtWidgets import ( - QGridLayout, - QGroupBox, - QLabel, - QSizePolicy, - QVBoxLayout, -) - -from game import Game -from game.ato.flight import Flight -from game.ato.flightmember import FlightMember -from game.data.weapons import Pylon -from qt_ui.blocksignals import block_signals -from qt_ui.windows.mission.flight.payload.QPylonEditor import QPylonEditor - - -class QLoadoutEditor(QGroupBox): - def __init__(self, flight: Flight, flight_member: FlightMember, game: Game) -> None: - super().__init__("Use custom loadout") - self.flight = flight - self.flight_member = flight_member - self.game = game - self.setCheckable(True) - self.setChecked(flight_member.loadout.is_custom) - - vbox = QVBoxLayout(self) - layout = QGridLayout(self) - - for i, pylon in enumerate(Pylon.iter_pylons(self.flight.unit_type)): - label = QLabel(f"{pylon.number}") - label.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) - layout.addWidget(label, i, 0) - layout.addWidget(QPylonEditor(game, flight, flight_member, pylon), i, 1) - - vbox.addLayout(layout) - vbox.addStretch() - self.setLayout(vbox) - - for pylon_editor in self.iter_pylon_editors(): - pylon_editor.set_from(self.flight_member.loadout) - - def iter_pylon_editors(self) -> Iterator[QPylonEditor]: - yield from self.findChildren(QPylonEditor) - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - with block_signals(self): - self.setChecked(self.flight_member.use_custom_loadout) - for pylon_editor in self.iter_pylon_editors(): - pylon_editor.set_flight_member(flight_member) - - def reset_pylons(self) -> None: - self.flight_member.use_custom_loadout = self.isChecked() - if not self.isChecked(): - for pylon_editor in self.iter_pylon_editors(): - pylon_editor.set_from(self.flight_member.loadout) diff --git a/qt_ui/windows/mission/flight/payload/QPylonEditor.py b/qt_ui/windows/mission/flight/payload/QPylonEditor.py deleted file mode 100644 index 5e3d013ce..000000000 --- a/qt_ui/windows/mission/flight/payload/QPylonEditor.py +++ /dev/null @@ -1,82 +0,0 @@ -import logging -import operator -from typing import Optional - -from PySide6.QtWidgets import QComboBox - -from game import Game -from game.ato.flight import Flight -from game.ato.flightmember import FlightMember -from game.ato.loadouts import Loadout -from game.data.weapons import Pylon, Weapon - - -class QPylonEditor(QComboBox): - def __init__( - self, game: Game, flight: Flight, flight_member: FlightMember, pylon: Pylon - ) -> None: - super().__init__() - self.flight = flight - self.flight_member = flight_member - self.pylon = pylon - self.game = game - self.has_added_clean_item = False - - current = self.flight_member.loadout.pylons.get(self.pylon.number) - - self.addItem("None", None) - if self.game.settings.restrict_weapons_by_date: - weapons = pylon.available_on(self.game.date) - else: - weapons = pylon.allowed - allowed = sorted(weapons, key=operator.attrgetter("name")) - for i, weapon in enumerate(allowed): - self.addItem(weapon.name, weapon) - if current == weapon: - self.setCurrentIndex(i + 1) - - self.currentIndexChanged.connect(self.on_pylon_change) - - def on_pylon_change(self): - selected: Optional[Weapon] = self.currentData() - self.flight_member.loadout.pylons[self.pylon.number] = selected - - if selected is None: - logging.debug(f"Pylon {self.pylon.number} emptied") - else: - logging.debug(f"Pylon {self.pylon.number} changed to {selected.name}") - - def weapon_from_loadout(self, loadout: Loadout) -> Optional[Weapon]: - weapon = loadout.pylons.get(self.pylon.number) - if weapon is None: - return None - # TODO: Fix pydcs to support the "weapon". - # These are not exported in the pydcs weapon map, which causes the pydcs pylon - # exporter to fail to include them in the supported list. Since they aren't - # known to be compatible (and we can't show them as compatible for *every* - # pylon, because they aren't), we won't have populated a "Clean" weapon when - # creating the selection list, so it's not selectable. To work around this, add - # the item to the list the first time it's encountered for the pylon. - # - # A similar hack exists in Pylon to support forcibly equipping this even when - # it's not known to be compatible. - if weapon.clsid == "": - if not self.has_added_clean_item: - self.addItem("Clean", weapon) - self.has_added_clean_item = True - return weapon - - def matching_weapon_name(self, loadout: Loadout) -> str: - if self.game.settings.restrict_weapons_by_date: - loadout = loadout.degrade_for_date(self.flight.unit_type, self.game.date) - weapon = self.weapon_from_loadout(loadout) - if weapon is None: - return "None" - return weapon.name - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.set_from(self.flight_member.loadout) - - def set_from(self, loadout: Loadout) -> None: - self.setCurrentText(self.matching_weapon_name(loadout)) diff --git a/qt_ui/windows/mission/flight/payload/missingpropertydataerror.py b/qt_ui/windows/mission/flight/payload/missingpropertydataerror.py deleted file mode 100644 index d46f307fa..000000000 --- a/qt_ui/windows/mission/flight/payload/missingpropertydataerror.py +++ /dev/null @@ -1,2 +0,0 @@ -class MissingPropertyDataError(RuntimeError): - ... diff --git a/qt_ui/windows/mission/flight/payload/ownlasercodeinfo.py b/qt_ui/windows/mission/flight/payload/ownlasercodeinfo.py deleted file mode 100644 index a28b04f33..000000000 --- a/qt_ui/windows/mission/flight/payload/ownlasercodeinfo.py +++ /dev/null @@ -1,56 +0,0 @@ -from PySide6.QtCore import Signal -from PySide6.QtWidgets import QWidget, QHBoxLayout, QLabel, QPushButton - -from game import Game -from game.ato.flightmember import FlightMember - - -class OwnLaserCodeInfo(QHBoxLayout): - assigned_laser_code_changed = Signal() - - def __init__( - self, game: Game, flight_member: FlightMember, parent: QWidget | None = None - ) -> None: - super().__init__(parent) - self.game = game - self.flight_member = flight_member - - self.addWidget(QLabel("Assigned TGP laser code:")) - self.addStretch() - - self.code_display = QLabel() - self.addWidget(self.code_display) - - self.alloc_dealloc_button = QPushButton() - self.alloc_dealloc_button.clicked.connect(self.on_alloc_dealloc_clicked) - self.addWidget(self.alloc_dealloc_button) - - self.bind_to_selected_member() - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.bind_to_selected_member() - - def bind_to_selected_member(self) -> None: - if (code := self.flight_member.tgp_laser_code) is not None: - self.alloc_dealloc_button.setEnabled(True) - self.alloc_dealloc_button.setText("Release") - self.code_display.setText(f"{code}") - elif self.flight_member.is_player: - self.alloc_dealloc_button.setText("Assign") - self.alloc_dealloc_button.setEnabled(True) - self.code_display.setText("Not assigned") - else: - self.alloc_dealloc_button.setText("Assign") - self.alloc_dealloc_button.setEnabled(False) - self.code_display.setText("AI does not use laser codes") - - def on_alloc_dealloc_clicked(self) -> None: - if self.flight_member.tgp_laser_code is not None: - self.flight_member.release_tgp_laser_code() - else: - self.flight_member.assign_tgp_laser_code( - self.game.laser_code_registry.alloc_laser_code() - ) - self.bind_to_selected_member() - self.assigned_laser_code_changed.emit() diff --git a/qt_ui/windows/mission/flight/payload/propertycheckbox.py b/qt_ui/windows/mission/flight/payload/propertycheckbox.py deleted file mode 100644 index f5d1caee9..000000000 --- a/qt_ui/windows/mission/flight/payload/propertycheckbox.py +++ /dev/null @@ -1,31 +0,0 @@ -from PySide6.QtWidgets import QCheckBox -from dcs.unitpropertydescription import UnitPropertyDescription - -from game.ato.flightmember import FlightMember -from .missingpropertydataerror import MissingPropertyDataError - - -class PropertyCheckBox(QCheckBox): - def __init__( - self, flight_member: FlightMember, prop: UnitPropertyDescription - ) -> None: - super().__init__() - self.flight_member = flight_member - self.prop = prop - - if prop.default is None: - raise MissingPropertyDataError("default cannot be None") - - self.setChecked( - self.flight_member.properties.get(self.prop.identifier, self.prop.default) - ) - self.toggled.connect(self.on_toggle) - - def on_toggle(self, checked: bool) -> None: - self.flight_member.properties[self.prop.identifier] = checked - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.setChecked( - self.flight_member.properties.get(self.prop.identifier, self.prop.default) - ) diff --git a/qt_ui/windows/mission/flight/payload/propertycombobox.py b/qt_ui/windows/mission/flight/payload/propertycombobox.py deleted file mode 100644 index 0d407982a..000000000 --- a/qt_ui/windows/mission/flight/payload/propertycombobox.py +++ /dev/null @@ -1,41 +0,0 @@ -from PySide6.QtWidgets import QComboBox -from dcs.unitpropertydescription import UnitPropertyDescription - -from game.ato.flightmember import FlightMember -from .missingpropertydataerror import MissingPropertyDataError - - -class PropertyComboBox(QComboBox): - def __init__( - self, flight_member: FlightMember, prop: UnitPropertyDescription - ) -> None: - super().__init__() - self.flight_member = flight_member - self.prop = prop - - if prop.values is None: - raise MissingPropertyDataError("values cannot be None") - if prop.default is None: - raise MissingPropertyDataError("default cannot be None") - - current_value = self.flight_member.properties.get( - self.prop.identifier, self.prop.default - ) - - for ident, text in self.prop.values.items(): - self.addItem(text, ident) - if ident == current_value: - self.setCurrentText(text) - - self.currentIndexChanged.connect(self.on_selection_changed) - - def on_selection_changed(self, _index: int) -> None: - self.flight_member.properties[self.prop.identifier] = self.currentData() - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.setCurrentText( - self.flight_member.properties.get( - self.prop.identifier, self.prop.values[self.prop.default] - ) - ) diff --git a/qt_ui/windows/mission/flight/payload/propertyeditor.py b/qt_ui/windows/mission/flight/payload/propertyeditor.py deleted file mode 100644 index fa825e761..000000000 --- a/qt_ui/windows/mission/flight/payload/propertyeditor.py +++ /dev/null @@ -1,98 +0,0 @@ -import itertools -import logging -from typing import Callable - -from PySide6.QtWidgets import QGridLayout, QLabel, QWidget -from dcs.unitpropertydescription import UnitPropertyDescription - -from game.ato import Flight -from game.ato.flightmember import FlightMember -from .missingpropertydataerror import MissingPropertyDataError -from .propertycheckbox import PropertyCheckBox -from .propertycombobox import PropertyComboBox -from .propertyspinbox import PropertySpinBox - - -class UnhandledControlTypeError(RuntimeError): - def __init__(self, control: str) -> None: - super().__init__(f"Unhandled control type {control}") - - -class PropertyEditor(QGridLayout): - def __init__(self, flight: Flight, flight_member: FlightMember) -> None: - super().__init__() - self.flight_member = flight_member - self.flight_member_update_listeners: list[Callable[[FlightMember], None]] = [] - - last_label: QWidget | None = None - row = itertools.count() - for prop in flight.unit_type.iter_props(): - if prop.label is None: - if prop.control != "label": - logging.error( - "Found non-label aircraft property with no display name." - ) - continue - - if prop.player_only and not flight.client_count: - continue - - if not flight.unit_type.should_show_prop(prop.identifier): - continue - - try: - widget = self.control_for_property(prop) - except (MissingPropertyDataError, UnhandledControlTypeError): - logging.exception( - f"Cannot create property control for property %s of %s", - prop.identifier, - flight.unit_type, - ) - continue - - # Draw any deferred label if this is a real control. - if last_label is not None and widget is not None: - self.addWidget(last_label, next(row), 0) - last_label = None - - label = prop.label - if widget is None: - label = f"{label}" - - label = QLabel(label) - if widget is None: - # The "control" is only a section label. Defer adding it to the layout - # so that we can skip empty sections. - last_label = label - else: - # Else the label is for the control itself and should be drawn - # immediately. - this_row = next(row) - self.addWidget(label, this_row, 0) - self.addWidget(widget, this_row, 1) - - def control_for_property(self, prop: UnitPropertyDescription) -> QWidget | None: - # Valid values are: - # "checkbox", "comboList", "groupbox", "label", "slider", "spinbox" - match prop.control: - case "checkbox": - widget = PropertyCheckBox(self.flight_member, prop) - self.flight_member_update_listeners.append(widget.set_flight_member) - return widget - case "comboList": - widget = PropertyComboBox(self.flight_member, prop) - self.flight_member_update_listeners.append(widget.set_flight_member) - return widget - case "groupbox" | "label": - return None - case "slider" | "spinbox": - widget = PropertySpinBox(self.flight_member, prop) - self.flight_member_update_listeners.append(widget.set_flight_member) - return widget - case _: - raise UnhandledControlTypeError(prop.control) - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - for listener in self.flight_member_update_listeners: - listener(self.flight_member) diff --git a/qt_ui/windows/mission/flight/payload/propertyspinbox.py b/qt_ui/windows/mission/flight/payload/propertyspinbox.py deleted file mode 100644 index f9a52913f..000000000 --- a/qt_ui/windows/mission/flight/payload/propertyspinbox.py +++ /dev/null @@ -1,38 +0,0 @@ -from PySide6.QtWidgets import QSpinBox -from dcs.unitpropertydescription import UnitPropertyDescription - -from game.ato.flightmember import FlightMember -from .missingpropertydataerror import MissingPropertyDataError - - -class PropertySpinBox(QSpinBox): - def __init__( - self, flight_member: FlightMember, prop: UnitPropertyDescription - ) -> None: - super().__init__() - self.flight_member = flight_member - self.prop = prop - - if prop.minimum is None: - raise MissingPropertyDataError("minimum cannot be None") - if prop.maximum is None: - raise MissingPropertyDataError("maximum cannot be None") - if prop.default is None: - raise MissingPropertyDataError("default cannot be None") - - self.setMinimum(prop.minimum) - self.setMaximum(prop.maximum) - self.setValue( - self.flight_member.properties.get(self.prop.identifier, self.prop.default) - ) - - self.valueChanged.connect(self.on_value_changed) - - def on_value_changed(self, value: int) -> None: - self.flight_member.properties[self.prop.identifier] = value - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.setValue( - self.flight_member.properties.get(self.prop.identifier, self.prop.default) - ) diff --git a/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py b/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py deleted file mode 100644 index 6b3b3f59f..000000000 --- a/qt_ui/windows/mission/flight/payload/weaponlasercodeselector.py +++ /dev/null @@ -1,51 +0,0 @@ -from PySide6.QtWidgets import QComboBox, QWidget - -from game import Game -from game.ato.flightmember import FlightMember -from qt_ui.blocksignals import block_signals - - -class WeaponLaserCodeSelector(QComboBox): - def __init__( - self, game: Game, flight_member: FlightMember, parent: QWidget | None = None - ) -> None: - super().__init__(parent) - self.game = game - self.flight_member = flight_member - self.currentIndexChanged.connect(self.on_index_changed) - - self.rebuild() - - def set_flight_member(self, flight_member: FlightMember) -> None: - self.flight_member = flight_member - self.rebuild() - - def on_index_changed(self) -> None: - self.flight_member.weapon_laser_code = self.currentData() - - def rebuild(self) -> None: - with block_signals(self): - self.clear() - if not self.flight_member.is_player: - self.setDisabled(True) - self.addItem("AI does not use laser codes", None) - - self.setEnabled(True) - - self.addItem("Default (1688)", None) - selected_index: int | None = None - idx = 1 - if (own := self.flight_member.tgp_laser_code) is not None: - self.addItem(f"Use own code ({own})", own) - if own == self.flight_member.weapon_laser_code: - selected_index = idx - idx += 1 - for idx, front in enumerate(self.game.theater.conflicts(), idx): - self.addItem( - f"JTAC {front.name} ({front.laser_code})", front.laser_code - ) - if front.laser_code == self.flight_member.weapon_laser_code: - selected_index = idx - - if selected_index is not None: - self.setCurrentIndex(selected_index) diff --git a/qt_ui/windows/mission/flight/settings/FlightPlanPropertiesGroup.py b/qt_ui/windows/mission/flight/settings/FlightPlanPropertiesGroup.py deleted file mode 100644 index 75ea97d1e..000000000 --- a/qt_ui/windows/mission/flight/settings/FlightPlanPropertiesGroup.py +++ /dev/null @@ -1,128 +0,0 @@ -import logging -from datetime import timedelta - -from PySide6.QtCore import QTime -from PySide6.QtWidgets import ( - QGroupBox, - QLabel, - QMessageBox, - QVBoxLayout, - QTimeEdit, - QHBoxLayout, - QCheckBox, -) - -from game import Game -from game.ato.flight import Flight -from game.ato.flightplans.planningerror import PlanningError -from qt_ui.models import PackageModel -from qt_ui.widgets.QLabeledWidget import QLabeledWidget -from qt_ui.widgets.combos.QArrivalAirfieldSelector import QArrivalAirfieldSelector - - -class FlightPlanPropertiesGroup(QGroupBox): - def __init__(self, game: Game, package_model: PackageModel, flight: Flight) -> None: - super().__init__("Flight plan properties") - self.game = game - self.package_model = package_model - self.flight = flight - - layout = QVBoxLayout() - - self.departure_time = QLabel() - layout.addLayout( - QLabeledWidget( - f"Departing from {flight.departure.name}", self.departure_time - ) - ) - self.package_model.tot_changed.connect(self.update_departure_time) - self.update_departure_time() - - tot_offset_layout = QHBoxLayout() - layout.addLayout(tot_offset_layout) - - delay = int(self.flight.flight_plan.tot_offset.total_seconds()) - negative = delay < 0 - if negative: - delay = -delay - hours = delay // 3600 - minutes = delay // 60 % 60 - seconds = delay % 60 - - tot_offset_layout.addWidget(QLabel("TOT Offset (minutes:seconds)")) - tot_offset_layout.addStretch() - self.negative_offset_checkbox = QCheckBox("Ahead of package") - self.negative_offset_checkbox.setChecked(negative) - self.negative_offset_checkbox.toggled.connect(self.toggle_negative_offset) - tot_offset_layout.addWidget(self.negative_offset_checkbox) - - self.tot_offset_spinner = QTimeEdit(QTime(hours, minutes, seconds)) - self.tot_offset_spinner.setMaximumTime(QTime(59, 0)) - self.tot_offset_spinner.setDisplayFormat("mm:ss") - self.tot_offset_spinner.timeChanged.connect(self.set_tot_offset) - self.tot_offset_spinner.setToolTip("Flight TOT offset from package TOT") - tot_offset_layout.addWidget(self.tot_offset_spinner) - - layout.addWidget( - QLabel( - "Determined based on the package TOT. Edit the " - "package to adjust the TOT." - ) - ) - - arrival_label = QLabel(f"{flight.arrival.name}") - layout.addLayout(QLabeledWidget("Arrival:", arrival_label)) - - self.divert = QArrivalAirfieldSelector( - [cp for cp in game.theater.controlpoints if cp.captured], - flight.unit_type, - "None", - ) - self.divert.currentIndexChanged.connect(self.set_divert) - if flight.divert is not None: - self.divert.setCurrentText(flight.divert.name) - layout.addLayout(QLabeledWidget("Divert:", self.divert)) - - self.setLayout(layout) - - def update_departure_time(self) -> None: - if not self.flight.package.flights: - # This is theoretically impossible, but for some reason the dialog that owns - # this object QEditFlightDialog does not dispose properly on close, so this - # handler may be called for a flight whose package has been canceled, which - # is an invalid state for calling anything in TotEstimator. - return - self.departure_time.setText( - f"At {self.flight.flight_plan.startup_time():%H:%M:%S}" - ) - - def set_divert(self, index: int) -> None: - old_divert = self.flight.divert - divert = self.divert.itemData(index) - if divert == old_divert: - return - - self.flight.divert = divert - try: - self.flight.recreate_flight_plan() - except PlanningError as ex: - self.flight.divert = old_divert - logging.exception("Could not change divert airfield") - QMessageBox.critical( - self, "Could not update flight plan", str(ex), QMessageBox.Ok - ) - - def set_tot_offset(self, offset: QTime) -> None: - offset = timedelta( - hours=offset.hour(), minutes=offset.minute(), seconds=offset.second() - ) - if self.negative_offset_checkbox.isChecked(): - offset = -offset - self.flight.flight_plan.tot_offset = offset - self.package_model.update_tot() - self.update_departure_time() - - def toggle_negative_offset(self) -> None: - self.flight.flight_plan.tot_offset = -self.flight.flight_plan.tot_offset - self.package_model.update_tot() - self.update_departure_time() diff --git a/qt_ui/windows/mission/flight/settings/QCustomName.py b/qt_ui/windows/mission/flight/settings/QCustomName.py deleted file mode 100644 index 67cf1cfdd..000000000 --- a/qt_ui/windows/mission/flight/settings/QCustomName.py +++ /dev/null @@ -1,15 +0,0 @@ -from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel - -from game.ato.flight import Flight - - -class QFlightCustomName(QGroupBox): - def __init__(self, flight: Flight): - super(QFlightCustomName, self).__init__() - - self.flight = flight - - self.layout = QHBoxLayout() - self.custom_name_label = QLabel(f"Custom Name: {flight.custom_name}") - self.layout.addWidget(self.custom_name_label) - self.setLayout(self.layout) diff --git a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py b/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py deleted file mode 100644 index e14687d4c..000000000 --- a/qt_ui/windows/mission/flight/settings/QFlightSlotEditor.py +++ /dev/null @@ -1,266 +0,0 @@ -import logging -from typing import Optional, Callable - -from PySide6.QtCore import Signal, QModelIndex -from PySide6.QtWidgets import ( - QLabel, - QGroupBox, - QSpinBox, - QGridLayout, - QComboBox, - QHBoxLayout, - QCheckBox, - QVBoxLayout, -) - -from game import Game -from game.ato.flight import Flight -from game.ato.flightroster import FlightRoster -from game.ato.iflightroster import IFlightRoster -from game.squadrons import Squadron -from game.squadrons.pilot import Pilot -from qt_ui.models import PackageModel - - -class PilotSelector(QComboBox): - available_pilots_changed = Signal() - - def __init__( - self, squadron: Squadron | None, roster: Optional[IFlightRoster], idx: int - ) -> None: - super().__init__() - self.squadron = squadron - self.roster = roster - self.pilot_index = idx - self.rebuild() - - @staticmethod - def text_for(pilot: Pilot) -> str: - return pilot.name - - def _do_rebuild(self) -> None: - self.clear() - if self.roster is None or self.pilot_index >= self.roster.max_size: - self.addItem("No aircraft", None) - self.setDisabled(True) - return - - if self.squadron is None: - raise RuntimeError("squadron cannot be None if roster is set") - - self.setEnabled(True) - self.addItem("Unassigned", None) - choices = list(self.squadron.available_pilots) - current_pilot = self.roster.pilot_at(self.pilot_index) - if current_pilot is not None: - choices.append(current_pilot) - # Put players first, otherwise alphabetically. - for pilot in sorted(choices, key=lambda p: (not p.player, p.name)): - self.addItem(self.text_for(pilot), pilot) - if current_pilot is None: - self.setCurrentText("Unassigned") - else: - self.setCurrentText(self.text_for(current_pilot)) - self.currentIndexChanged.connect(self.replace_pilot) - - def rebuild(self) -> None: - # The contents of the selector depend on the selection of the other selectors - # for the flight, so changing the selection of one causes each selector to - # rebuild. A rebuild causes a selection change, so if we don't block signals - # during a rebuild we'll never stop rebuilding. - self.blockSignals(True) - try: - self._do_rebuild() - finally: - self.blockSignals(False) - - def replace_pilot(self, index: QModelIndex) -> None: - if self.itemText(index) == "No aircraft": - # The roster resize is handled separately, so we have no pilots to remove. - return - pilot = self.itemData(index) - if pilot == self.roster.pilot_at(self.pilot_index): - return - self.roster.set_pilot(self.pilot_index, pilot) - self.available_pilots_changed.emit() - - def replace( - self, squadron: Squadron | None, new_roster: Optional[FlightRoster] - ) -> None: - self.squadron = squadron - self.roster = new_roster - self.rebuild() - - -class PilotControls(QHBoxLayout): - def __init__( - self, squadron: Squadron | None, roster: Optional[FlightRoster], idx: int - ) -> None: - super().__init__() - self.roster = roster - self.pilot_index = idx - - self.selector = PilotSelector(squadron, roster, idx) - self.selector.currentIndexChanged.connect(self.on_pilot_changed) - self.addWidget(self.selector) - - self.player_checkbox = QCheckBox(text="Player") - self.player_checkbox.setToolTip("Checked if this pilot is a player.") - self.on_pilot_changed(self.selector.currentIndex()) - enabled = False - if self.roster is not None and squadron is not None: - enabled = squadron.aircraft.flyable - self.player_checkbox.setEnabled(enabled) - self.addWidget(self.player_checkbox) - - self.player_checkbox.toggled.connect(self.on_player_toggled) - - @property - def pilot(self) -> Optional[Pilot]: - if self.roster is None or self.pilot_index >= self.roster.max_size: - return None - return self.roster.pilot_at(self.pilot_index) - - def on_player_toggled(self, checked: bool) -> None: - pilot = self.pilot - if pilot is None: - logging.error("Cannot toggle state of a pilot when none is selected") - return - pilot.player = checked - - def on_pilot_changed(self, index: int) -> None: - pilot = self.selector.itemData(index) - self.player_checkbox.blockSignals(True) - try: - self.player_checkbox.setChecked(pilot is not None and pilot.player) - finally: - self.player_checkbox.blockSignals(False) - - def update_available_pilots(self) -> None: - self.selector.rebuild() - - def enable_and_reset(self) -> None: - self.selector.rebuild() - self.player_checkbox.setEnabled(True) - self.on_pilot_changed(self.selector.currentIndex()) - - def disable_and_clear(self) -> None: - self.selector.rebuild() - self.player_checkbox.blockSignals(True) - try: - self.player_checkbox.setEnabled(False) - self.player_checkbox.setChecked(False) - finally: - self.player_checkbox.blockSignals(False) - - def replace(self, squadron: Squadron, new_roster: Optional[FlightRoster]) -> None: - self.roster = new_roster - if self.roster is None or self.pilot_index >= self.roster.max_size: - self.disable_and_clear() - else: - self.enable_and_reset() - self.selector.replace(squadron, new_roster) - - -class FlightRosterEditor(QVBoxLayout): - MAX_PILOTS = 4 - - def __init__(self, squadron: Squadron | None, roster: IFlightRoster | None) -> None: - super().__init__() - self.roster = roster - - self.pilot_controls = [] - for pilot_idx in range(self.MAX_PILOTS): - - def make_reset_callback(source_idx: int) -> Callable[[int], None]: - def callback() -> None: - self.update_available_pilots(source_idx) - - return callback - - controls = PilotControls(squadron, roster, pilot_idx) - controls.selector.available_pilots_changed.connect( - make_reset_callback(pilot_idx) - ) - self.pilot_controls.append(controls) - self.addLayout(controls) - - def update_available_pilots(self, source_idx: int) -> None: - for idx, controls in enumerate(self.pilot_controls): - # No need to reset the source of the reset, it was just manually selected. - if idx != source_idx: - controls.update_available_pilots() - - def resize(self, new_size: int) -> None: - if new_size > self.MAX_PILOTS: - raise ValueError("A flight may not have more than four pilots.") - if self.roster is not None: - self.roster.resize(new_size) - for controls in self.pilot_controls[:new_size]: - controls.enable_and_reset() - for controls in self.pilot_controls[new_size:]: - controls.disable_and_clear() - - def replace( - self, squadron: Squadron | None, new_roster: Optional[FlightRoster] - ) -> None: - if self.roster is not None: - self.roster.clear() - self.roster = new_roster - for controls in self.pilot_controls: - controls.replace(squadron, new_roster) - - -class QFlightSlotEditor(QGroupBox): - flight_resized = Signal(int) - - def __init__(self, package_model: PackageModel, flight: Flight, game: Game): - super().__init__("Slots") - self.package_model = package_model - self.flight = flight - self.game = game - available = self.flight.squadron.untasked_aircraft - max_count = self.flight.count + available - if max_count > 4: - max_count = 4 - - layout = QGridLayout() - - self.aircraft_count = QLabel("Aircraft count:") - self.aircraft_count_spinner = QSpinBox() - self.aircraft_count_spinner.setMinimum(1) - self.aircraft_count_spinner.setMaximum(max_count) - self.aircraft_count_spinner.setValue(flight.count) - self.aircraft_count_spinner.valueChanged.connect(self._changed_aircraft_count) - - layout.addWidget(self.aircraft_count, 0, 0) - layout.addWidget(self.aircraft_count_spinner, 0, 1) - - layout.addWidget(QLabel("Squadron:"), 1, 0) - layout.addWidget(QLabel(str(self.flight.squadron)), 1, 1) - - layout.addWidget(QLabel("Assigned pilots:"), 2, 0) - self.roster_editor = FlightRosterEditor(flight.squadron, flight.roster) - layout.addLayout(self.roster_editor, 2, 1) - - self.setLayout(layout) - - def _changed_aircraft_count(self): - old_count = self.flight.count - new_count = int(self.aircraft_count_spinner.value()) - try: - self.flight.resize(new_count) - except ValueError: - # The UI should have prevented this, but if we ran out of aircraft - # then roll back the inventory change. - difference = new_count - self.flight.count - available = self.flight.squadron.untasked_aircraft - logging.error( - f"Could not add {difference} additional aircraft to " - f"{self.flight} because {self.flight.departure} has only " - f"{available} {self.flight.unit_type} remaining" - ) - self.flight.resize(old_count) - return - self.roster_editor.resize(new_count) - self.flight_resized.emit(new_count) diff --git a/qt_ui/windows/mission/flight/settings/QFlightStartType.py b/qt_ui/windows/mission/flight/settings/QFlightStartType.py deleted file mode 100644 index 82c73cf07..000000000 --- a/qt_ui/windows/mission/flight/settings/QFlightStartType.py +++ /dev/null @@ -1,49 +0,0 @@ -from PySide6.QtWidgets import ( - QComboBox, - QGroupBox, - QHBoxLayout, - QLabel, - QVBoxLayout, -) - -from game.ato.flight import Flight -from game.ato.starttype import StartType -from game.theater import OffMapSpawn -from qt_ui.models import PackageModel - - -class QFlightStartType(QGroupBox): - def __init__(self, package_model: PackageModel, flight: Flight): - super().__init__() - self.package_model = package_model - self.flight = flight - - self.layout = QVBoxLayout() - self.main_row = QHBoxLayout() - self.start_type_label = QLabel("Start type:") - self.start_type = QComboBox() - - for start_type in StartType: - self.start_type.addItem(start_type.value, start_type) - self.start_type.setCurrentText(flight.start_type.value) - - if isinstance(self.flight.departure, OffMapSpawn): - self.start_type.setEnabled(False) - - self.start_type.currentTextChanged.connect(self._on_start_type_selected) - self.main_row.addWidget(self.start_type_label) - self.main_row.addWidget(self.start_type) - - self.layout.addLayout(self.main_row) - self.layout.addWidget( - QLabel( - "Any option other than Cold will make this flight non-targetable " - + "by OCA/Aircraft missions. This will affect game balance." - ) - ) - self.setLayout(self.layout) - - def _on_start_type_selected(self): - selected = self.start_type.currentData() - self.flight.start_type = selected - self.package_model.update_tot() diff --git a/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py b/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py deleted file mode 100644 index 4aa1fbe9a..000000000 --- a/qt_ui/windows/mission/flight/settings/QFlightTypeTaskInfo.py +++ /dev/null @@ -1,26 +0,0 @@ -from PySide6.QtWidgets import QLabel, QGroupBox, QGridLayout - -from qt_ui.uiconstants import AIRCRAFT_ICONS - - -class QFlightTypeTaskInfo(QGroupBox): - def __init__(self, flight): - super(QFlightTypeTaskInfo, self).__init__("Flight") - self.flight = flight - - layout = QGridLayout() - - self.aircraft_icon = QLabel() - if self.flight.unit_type.dcs_id in AIRCRAFT_ICONS: - self.aircraft_icon.setPixmap(AIRCRAFT_ICONS[self.flight.unit_type.dcs_id]) - - self.task = QLabel("Task:") - self.task_type = QLabel(str(flight.flight_type)) - self.task_type.setProperty("style", flight.flight_type.name) - - layout.addWidget(self.aircraft_icon, 0, 0) - - layout.addWidget(self.task, 1, 0) - layout.addWidget(self.task_type, 1, 1) - - self.setLayout(layout) diff --git a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py b/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py deleted file mode 100644 index b3a753e32..000000000 --- a/qt_ui/windows/mission/flight/settings/QGeneralFlightSettingsTab.py +++ /dev/null @@ -1,35 +0,0 @@ -from PySide6.QtCore import Signal -from PySide6.QtWidgets import QFrame, QGridLayout, QVBoxLayout - -from game import Game -from game.ato.flight import Flight -from qt_ui.models import PackageModel -from qt_ui.windows.mission.flight.settings.FlightPlanPropertiesGroup import ( - FlightPlanPropertiesGroup, -) -from qt_ui.windows.mission.flight.settings.QCustomName import QFlightCustomName -from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import QFlightSlotEditor -from qt_ui.windows.mission.flight.settings.QFlightStartType import QFlightStartType -from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import ( - QFlightTypeTaskInfo, -) - - -class QGeneralFlightSettingsTab(QFrame): - flight_size_changed = Signal() - - def __init__(self, game: Game, package_model: PackageModel, flight: Flight): - super().__init__() - - layout = QGridLayout() - layout.addWidget(QFlightTypeTaskInfo(flight), 0, 0) - layout.addWidget(FlightPlanPropertiesGroup(game, package_model, flight), 1, 0) - self.flight_slot_editor = QFlightSlotEditor(package_model, flight, game) - self.flight_slot_editor.flight_resized.connect(self.flight_size_changed) - layout.addWidget(self.flight_slot_editor, 2, 0) - layout.addWidget(QFlightStartType(package_model, flight), 3, 0) - layout.addWidget(QFlightCustomName(flight), 4, 0) - vstretch = QVBoxLayout() - vstretch.addStretch() - layout.addLayout(vstretch, 5, 0) - self.setLayout(layout) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py deleted file mode 100644 index 73435db2d..000000000 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py +++ /dev/null @@ -1,58 +0,0 @@ -from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout - -from game.ato.flightwaypoint import FlightWaypoint - - -class QFlightWaypointInfoBox(QGroupBox): - def __init__(self) -> None: - super(QFlightWaypointInfoBox, self).__init__("Waypoint") - self.x_position_label = QLabel("0") - self.y_position_label = QLabel("0") - self.alt_label = QLabel("0") - self.name_label = QLabel("") - self.desc_label = QLabel("") - self.init_ui() - - def init_ui(self) -> None: - layout = QVBoxLayout() - - x_pos_layout = QHBoxLayout() - x_pos_layout.addWidget(QLabel("X : ")) - x_pos_layout.addWidget(self.x_position_label) - x_pos_layout.addStretch() - - y_pos_layout = QHBoxLayout() - y_pos_layout.addWidget(QLabel("Y : ")) - y_pos_layout.addWidget(self.y_position_label) - y_pos_layout.addStretch() - - alt_layout = QHBoxLayout() - alt_layout.addWidget(QLabel("Alt : ")) - alt_layout.addWidget(self.alt_label) - alt_layout.addStretch() - - name_layout = QHBoxLayout() - name_layout.addWidget(QLabel("Name : ")) - name_layout.addWidget(self.name_label) - name_layout.addStretch() - - desc_layout = QHBoxLayout() - desc_layout.addWidget(QLabel("Description : ")) - desc_layout.addWidget(self.desc_label) - desc_layout.addStretch() - - # layout.addLayout(name_layout) - layout.addLayout(x_pos_layout) - layout.addLayout(y_pos_layout) - layout.addLayout(alt_layout) - layout.addLayout(desc_layout) - - self.setLayout(layout) - - def set_flight_waypoint(self, flight_wpt: FlightWaypoint) -> None: - self.x_position_label.setText(str(flight_wpt.x)) - self.y_position_label.setText(str(flight_wpt.y)) - self.alt_label.setText(str(int(flight_wpt.alt.feet))) - self.name_label.setText(str(flight_wpt.name)) - self.desc_label.setText(str(flight_wpt.description)) - self.setTitle(flight_wpt.name) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py deleted file mode 100644 index 175120952..000000000 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointItem.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import List - -from PySide6.QtGui import QStandardItem - -from game.ato.flightwaypoint import FlightWaypoint - - -class QWaypointItem(QStandardItem): - def __init__(self, point: FlightWaypoint, number): - super(QWaypointItem, self).__init__() - self.number = number - self.setText("{:<16}".format(point.pretty_name)) - self.setEditable(False) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py deleted file mode 100644 index a8266e7a7..000000000 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py +++ /dev/null @@ -1,137 +0,0 @@ -from PySide6.QtCore import QItemSelectionModel, QPoint, QModelIndex -from PySide6.QtGui import QStandardItem, QStandardItemModel -from PySide6.QtWidgets import ( - QHeaderView, - QTableView, - QStyledItemDelegate, - QDoubleSpinBox, - QWidget, - QStyleOptionViewItem, -) - -from game.ato.flight import Flight -from game.ato.flightwaypoint import FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.ato.package import Package -from game.utils import Distance -from qt_ui.windows.mission.flight.waypoints.QFlightWaypointItem import QWaypointItem - - -HEADER_LABELS = ["Name", "Alt (ft)", "Alt Type", "TOT/DEPART"] - - -class AltitudeEditorDelegate(QStyledItemDelegate): - def createEditor( - self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex - ) -> QDoubleSpinBox: - editor = QDoubleSpinBox(parent) - editor.setMinimum(0) - editor.setMaximum(40000) - return editor - - -class QFlightWaypointList(QTableView): - def __init__(self, package: Package, flight: Flight): - super().__init__() - self.package = package - self.flight = flight - - self.model = QStandardItemModel(self) - self.model.itemChanged.connect(self.on_changed) - self.setModel(self.model) - self.model.setHorizontalHeaderLabels(HEADER_LABELS) - - header = self.horizontalHeader() - header.setSectionResizeMode(0, QHeaderView.ResizeToContents) - self.update_list() - - self.selectionModel().setCurrentIndex( - self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select - ) - - self.altitude_editor_delegate = AltitudeEditorDelegate(self) - self.setItemDelegateForColumn(1, self.altitude_editor_delegate) - - def update_list(self) -> None: - # We need to keep just the row and rebuild the index later because the - # QModelIndex will not be valid after the model is cleared. - current_index = self.currentIndex().row() - self.model.clear() - - self.model.setHorizontalHeaderLabels(HEADER_LABELS) - - waypoints = self.flight.flight_plan.waypoints - # Why [1:]? Qt starts indexing at 1 rather than 0, whereas DCS numbers - # waypoints starting with 0, and for whatever reason Qt crashes whenever I - # set the vertical labels manually. - # - # Starting with the second waypoint is a bit of a hack, but it's also the - # historical behavior anyway. This view used to have waypoints starting at 1 - # and just didn't show the departure waypoint because the departure waypoint - # wasn't actually part of the flight plan tracked by Liberation. That - # changed at some point, so now we need to skip it manually to preserve that - # behavior. - # - # It really ought to show the departure waypoint and start indexing at 0, - # but since this all pending a move to React anyway, it's not worth fighting - # the Qt crashes for now. - # - # https://github.com/dcs-liberation/dcs_liberation/issues/3037 - for row, waypoint in enumerate(waypoints[1:]): - self._add_waypoint_row(row, self.flight, waypoint) - self.selectionModel().setCurrentIndex( - self.model.index(current_index, 0), QItemSelectionModel.Select - ) - self.resizeColumnsToContents() - total_column_width = self.verticalHeader().width() + self.lineWidth() - for i in range(0, self.model.columnCount()): - total_column_width += self.columnWidth(i) + self.lineWidth() - self.setFixedWidth(total_column_width) - - def _add_waypoint_row( - self, row: int, flight: Flight, waypoint: FlightWaypoint - ) -> None: - self.model.insertRow(self.model.rowCount()) - - self.model.setItem(row, 0, QWaypointItem(waypoint, row)) - - altitude = int(waypoint.alt.feet) - altitude_item = QStandardItem(f"{altitude}") - altitude_item.setEditable(True) - self.model.setItem(row, 1, altitude_item) - - altitude_type = "AGL" if waypoint.alt_type == "RADIO" else "MSL" - altitude_type_item = QStandardItem(f"{altitude_type}") - altitude_type_item.setEditable(False) - self.model.setItem(row, 2, altitude_type_item) - - tot = self.tot_text(flight, waypoint) - tot_item = QStandardItem(tot) - tot_item.setEditable(False) - self.model.setItem(row, 3, tot_item) - - def on_changed(self) -> None: - for i in range(self.model.rowCount()): - if self.model.item(i, 1) is not None: - altitude = self.model.item(i, 1).text() - altitude_feet = float(altitude) - # update waypoint index i+1 as rows are 1-indexed - self.flight.flight_plan.waypoints[i + 1].alt = Distance.from_feet( - altitude_feet - ) - - def tot_text(self, flight: Flight, waypoint: FlightWaypoint) -> str: - if waypoint.waypoint_type == FlightWaypointType.TAKEOFF: - return self.takeoff_text(flight) - prefix = "" - time = flight.flight_plan.tot_for_waypoint(waypoint) - if time is None: - prefix = "Depart " - time = flight.flight_plan.depart_time_for_waypoint(waypoint) - if time is None: - return "" - return f"{prefix}{time:%H:%M:%S}" - - @staticmethod - def takeoff_text(flight: Flight) -> str: - return f"{flight.flight_plan.takeoff_time():%H:%M:%S}" diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py deleted file mode 100644 index 852247d29..000000000 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py +++ /dev/null @@ -1,184 +0,0 @@ -import logging -from typing import Iterable, List, Optional - -from PySide6.QtCore import Signal -from PySide6.QtWidgets import ( - QFrame, - QGridLayout, - QLabel, - QMessageBox, - QPushButton, - QVBoxLayout, -) - -from game import Game -from game.ato.flight import Flight -from game.ato.flightplans.custom import CustomFlightPlan -from game.ato.flightplans.formationattack import FormationAttackFlightPlan -from game.ato.flightplans.planningerror import PlanningError -from game.ato.flightplans.waypointbuilder import WaypointBuilder -from game.ato.flighttype import FlightType -from game.ato.flightwaypoint import FlightWaypoint -from game.ato.loadouts import Loadout -from game.ato.package import Package -from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import ( - QFlightWaypointList, -) -from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import ( - QPredefinedWaypointSelectionWindow, -) - - -class QFlightWaypointTab(QFrame): - loadout_changed = Signal() - - def __init__(self, game: Game, package: Package, flight: Flight): - super(QFlightWaypointTab, self).__init__() - self.game = game - self.coalition = game.coalition_for(player=True) - self.package = package - self.flight = flight - - self.flight_waypoint_list: Optional[QFlightWaypointList] = None - self.rtb_waypoint: Optional[QPushButton] = None - self.delete_selected: Optional[QPushButton] = None - self.open_fast_waypoint_button: Optional[QPushButton] = None - self.recreate_buttons: List[QPushButton] = [] - self.init_ui() - - def init_ui(self): - layout = QGridLayout() - - self.flight_waypoint_list = QFlightWaypointList(self.package, self.flight) - layout.addWidget(self.flight_waypoint_list, 0, 0) - - rlayout = QVBoxLayout() - layout.addLayout(rlayout, 0, 1) - - rlayout.addWidget(QLabel("Generator :")) - rlayout.addWidget(QLabel("AI compatible")) - - self.recreate_buttons.clear() - for task in self.package.target.mission_types(for_player=True): - if ( - task == FlightType.AIR_ASSAULT - and not self.game.lua_plugin_manager.is_plugin_enabled("ctld") - ): - # Only add Air Assault if ctld plugin is enabled - continue - - def make_closure(arg): - def closure(): - return self.confirm_recreate(arg) - - return closure - - button = QPushButton(f"Recreate as {task}") - button.clicked.connect(make_closure(task)) - rlayout.addWidget(button) - self.recreate_buttons.append(button) - - rlayout.addWidget(QLabel("Advanced : ")) - rlayout.addWidget(QLabel("Do not use for AI flights")) - - self.rtb_waypoint = QPushButton("Add RTB Waypoint") - self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint) - rlayout.addWidget(self.rtb_waypoint) - - self.delete_selected = QPushButton("Delete Selected") - self.delete_selected.clicked.connect(self.on_delete_waypoint) - rlayout.addWidget(self.delete_selected) - - self.open_fast_waypoint_button = QPushButton("Add Waypoint") - self.open_fast_waypoint_button.clicked.connect(self.on_fast_waypoint) - rlayout.addWidget(self.open_fast_waypoint_button) - rlayout.addStretch() - self.setLayout(layout) - - def on_delete_waypoint(self): - waypoints = [] - selection = self.flight_waypoint_list.selectionModel() - for selected_row in selection.selectedIndexes(): - if selected_row.row() > 0: - waypoints.append( - self.flight.flight_plan.waypoints[selected_row.row() + 1] - ) - for waypoint in waypoints: - self.delete_waypoint(waypoint) - self.flight_waypoint_list.update_list() - self.on_change() - - def delete_waypoint(self, waypoint: FlightWaypoint) -> None: - # Need to degrade to a custom flight plan and remove the waypoint. - # If the waypoint is a target waypoint and is not the last target - # waypoint, we don't need to degrade. - if isinstance(self.flight.flight_plan, FormationAttackFlightPlan): - is_target = waypoint in self.flight.flight_plan.target_area_waypoint.targets - count = len(self.flight.flight_plan.target_area_waypoint.targets) - if is_target and count > 1: - self.flight.flight_plan.target_area_waypoint.targets.remove(waypoint) - return - - self.degrade_to_custom_flight_plan() - assert isinstance(self.flight.flight_plan, CustomFlightPlan) - self.flight.flight_plan.layout.custom_waypoints.remove(waypoint) - - def on_fast_waypoint(self): - self.subwindow = QPredefinedWaypointSelectionWindow( - self.game, self.flight, self.flight_waypoint_list - ) - self.subwindow.waypoints_added.connect(self.on_waypoints_added) - self.subwindow.show() - - def on_waypoints_added(self, waypoints: Iterable[FlightWaypoint]) -> None: - if not waypoints: - return - self.degrade_to_custom_flight_plan() - assert isinstance(self.flight.flight_plan, CustomFlightPlan) - self.flight.flight_plan.layout.custom_waypoints.extend(waypoints) - self.flight_waypoint_list.update_list() - self.on_change() - - def on_rtb_waypoint(self): - rtb = WaypointBuilder(self.flight, self.coalition).land(self.flight.arrival) - self.degrade_to_custom_flight_plan() - assert isinstance(self.flight.flight_plan, CustomFlightPlan) - self.flight.flight_plan.layout.custom_waypoints.append(rtb) - self.flight_waypoint_list.update_list() - self.on_change() - - def degrade_to_custom_flight_plan(self) -> None: - if not isinstance(self.flight.flight_plan, CustomFlightPlan): - self.flight.degrade_to_custom_flight_plan() - - def confirm_recreate(self, task: FlightType) -> None: - result = QMessageBox.question( - self, - "Regenerate flight?", - ( - "Changing the flight type will reset its flight plan. Do you want " - "to continue?" - ), - QMessageBox.No, - QMessageBox.Yes, - ) - original_task = self.flight.flight_type - if result == QMessageBox.Yes: - self.flight.set_flight_type(task) - try: - self.flight.recreate_flight_plan(dump_debug_info=True) - except PlanningError as ex: - self.flight.set_flight_type(original_task) - logging.exception("Could not recreate flight") - QMessageBox.critical( - self, "Could not recreate flight", str(ex), QMessageBox.Ok - ) - for member in self.flight.iter_members(): - if not member.loadout.is_custom: - member.loadout = Loadout.default_for(self.flight) - self.loadout_changed.emit() - self.flight_waypoint_list.update_list() - self.on_change() - - def on_change(self): - self.flight_waypoint_list.update_list() diff --git a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py b/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py deleted file mode 100644 index fd2740ba1..000000000 --- a/qt_ui/windows/mission/flight/waypoints/QPredefinedWaypointSelectionWindow.py +++ /dev/null @@ -1,93 +0,0 @@ -from PySide6.QtCore import Qt, Signal -from PySide6.QtWidgets import ( - QCheckBox, - QDialog, - QHBoxLayout, - QLabel, - QPushButton, - QVBoxLayout, -) - -from game import Game -from game.ato.flight import Flight -from qt_ui.uiconstants import EVENT_ICONS -from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import ( - QPredefinedWaypointSelectionComboBox, -) -from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import ( - QFlightWaypointInfoBox, -) - -PREDEFINED_WAYPOINT_CATEGORIES = [ - "Frontline (CAS AREA)", - "Building", - "Units", - "Airbase", -] - - -class QPredefinedWaypointSelectionWindow(QDialog): - # List of FlightWaypoint - waypoints_added = Signal(list) - - def __init__(self, game: Game, flight: Flight, flight_waypoint_list): - super(QPredefinedWaypointSelectionWindow, self).__init__() - self.game = game - self.flight = flight - self.setWindowFlags(Qt.WindowStaysOnTopHint) - self.setMinimumSize(400, 250) - self.setModal(True) - self.setWindowTitle("Add Predefined Waypoint") - self.setWindowIcon(EVENT_ICONS["strike"]) - self.flight_waypoint_list = flight_waypoint_list - - self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game) - self.wpt_selection_box.setMinimumWidth(200) - self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed) - self.selected_waypoints = [] - self.wpt_info = QFlightWaypointInfoBox() - - self.add_button = QPushButton("Add") - self.add_button.clicked.connect(self.add_waypoint) - - self.include_all = QCheckBox() - self.include_all.stateChanged.connect(self.on_select_wpt_changed) - self.include_all.setChecked(True) - - self.init_ui() - self.on_select_wpt_changed() - - def init_ui(self): - layout = QVBoxLayout() - - wpt_layout = QHBoxLayout() - wpt_layout.addWidget(QLabel("Waypoint : ")) - wpt_layout.addWidget(self.wpt_selection_box) - wpt_layout.addStretch() - - include_all = QHBoxLayout() - include_all.addWidget(QLabel("Include all objects from the same location : ")) - include_all.addWidget(self.include_all) - include_all.addStretch() - - layout.addLayout(wpt_layout) - layout.addWidget(self.wpt_info) - layout.addLayout(include_all) - layout.addStretch() - layout.addWidget(self.add_button) - - self.setLayout(layout) - - def on_select_wpt_changed(self): - self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints( - self.include_all.isChecked() - ) - if self.selected_waypoints is None or len(self.selected_waypoints) <= 0: - self.add_button.setDisabled(True) - else: - self.wpt_info.set_flight_waypoint(self.selected_waypoints[0]) - self.add_button.setDisabled(False) - - def add_waypoint(self): - self.waypoints_added.emit(self.selected_waypoints) - self.close() diff --git a/qt_ui/windows/newgame/QCampaignList.py b/qt_ui/windows/newgame/QCampaignList.py deleted file mode 100644 index a5a3cb7ef..000000000 --- a/qt_ui/windows/newgame/QCampaignList.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -from typing import Optional - -from PySide6 import QtGui -from PySide6.QtCore import QItemSelectionModel, QModelIndex, Qt -from PySide6.QtGui import QPixmap, QStandardItem, QStandardItemModel -from PySide6.QtWidgets import QAbstractItemView, QListView - -from game.campaignloader.campaign import Campaign -from qt_ui.liberation_install import get_dcs_install_directory - - -class QCampaignItem(QStandardItem): - def __init__(self, campaign: Campaign) -> None: - super(QCampaignItem, self).__init__() - self.setData(campaign, QCampaignList.CampaignRole) - dcs_path = get_dcs_install_directory() - icon_path = dcs_path / campaign.menu_thumbnail_dcs_relative_path - self.setIcon(QtGui.QIcon(QPixmap(str(icon_path)))) - self.setEditable(False) - if campaign.is_compatible: - name = campaign.name - else: - name = f"[INCOMPATIBLE] {campaign.name}" - self.setText(name) - - -class QCampaignList(QListView): - CampaignRole = Qt.UserRole - - def __init__(self, campaigns: list[Campaign], show_incompatible: bool) -> None: - super(QCampaignList, self).__init__() - self.campaign_model = QStandardItemModel(self) - self.setModel(self.campaign_model) - self.setMinimumWidth(250) - self.setMinimumHeight(350) - self.campaigns = campaigns - self.setSelectionBehavior(QAbstractItemView.SelectItems) - self.setup_content(show_incompatible) - - @property - def selected_campaign(self) -> Optional[Campaign]: - return self.currentIndex().data(QCampaignList.CampaignRole) - - def setup_content(self, show_incompatible: bool) -> None: - self.selectionModel().blockSignals(True) - try: - self.campaign_model.clear() - for campaign in self.campaigns: - if show_incompatible or campaign.is_compatible: - item = QCampaignItem(campaign) - self.campaign_model.appendRow(item) - finally: - self.selectionModel().blockSignals(False) - - self.selectionModel().setCurrentIndex( - self.campaign_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select - ) diff --git a/qt_ui/windows/newgame/QNewGameWizard.py b/qt_ui/windows/newgame/QNewGameWizard.py deleted file mode 100644 index bd62a0fe3..000000000 --- a/qt_ui/windows/newgame/QNewGameWizard.py +++ /dev/null @@ -1,915 +0,0 @@ -from __future__ import unicode_literals - -import logging -import textwrap -from datetime import datetime, timedelta -from typing import List - -from PySide6 import QtGui, QtWidgets -from PySide6.QtCore import QDate, QItemSelectionModel, QPoint, Qt, Signal -from PySide6.QtWidgets import ( - QCheckBox, - QLabel, - QScrollArea, - QTextEdit, - QVBoxLayout, - QWidget, - QDialog, -) -from jinja2 import Environment, FileSystemLoader, select_autoescape - -from game.campaignloader.campaign import Campaign, DEFAULT_BUDGET -from game.factions import Faction -from game.factions.factions import Factions -from game.plugins import LuaPlugin, LuaPluginManager -from game.plugins.luaplugin import LuaPluginOption -from game.settings import Settings -from game.theater.start_generator import GameGenerator, GeneratorSettings, ModSettings -from qt_ui.widgets.QLiberationCalendar import QLiberationCalendar -from qt_ui.widgets.spinsliders import CurrencySpinner, FloatSpinSlider, TimeInputs -from qt_ui.windows.AirWingConfigurationDialog import AirWingConfigurationDialog -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.newgame.QCampaignList import QCampaignList - -jinja_env = Environment( - loader=FileSystemLoader("resources/ui/templates"), - autoescape=select_autoescape( - disabled_extensions=("",), - default_for_string=True, - default=True, - ), - trim_blocks=True, - lstrip_blocks=True, -) - -""" -Possible time periods for new games - - `Name`: daytime(day, month, year), - -`Identifier` is the name that will appear in the menu -The object is a python datetime object -""" -TIME_PERIODS = { - "WW2 - Winter [1944]": datetime(1944, 1, 1), - "WW2 - Spring [1944]": datetime(1944, 4, 1), - "WW2 - Summer [1944]": datetime(1944, 6, 1), - "WW2 - Fall [1944]": datetime(1944, 10, 1), - "Early Cold War - Winter [1952]": datetime(1952, 1, 1), - "Early Cold War - Spring [1952]": datetime(1952, 4, 1), - "Early Cold War - Summer [1952]": datetime(1952, 6, 1), - "Early Cold War - Fall [1952]": datetime(1952, 10, 1), - "Cold War - Winter [1970]": datetime(1970, 1, 1), - "Cold War - Spring [1970]": datetime(1970, 4, 1), - "Cold War - Summer [1970]": datetime(1970, 6, 1), - "Cold War - Fall [1970]": datetime(1970, 10, 1), - "Late Cold War - Winter [1985]": datetime(1985, 1, 1), - "Late Cold War - Spring [1985]": datetime(1985, 4, 1), - "Late Cold War - Summer [1985]": datetime(1985, 6, 1), - "Late Cold War - Fall [1985]": datetime(1985, 10, 1), - "Gulf War - Winter [1990]": datetime(1990, 1, 1), - "Gulf War - Spring [1990]": datetime(1990, 4, 1), - "Gulf War - Summer [1990]": datetime(1990, 6, 1), - "Mid-90s - Winter [1995]": datetime(1995, 1, 1), - "Mid-90s - Spring [1995]": datetime(1995, 4, 1), - "Mid-90s - Summer [1995]": datetime(1995, 6, 1), - "Mid-90s - Fall [1995]": datetime(1995, 10, 1), - "Gulf War - Fall [1990]": datetime(1990, 10, 1), - "Modern - Winter [2010]": datetime(2010, 1, 1), - "Modern - Spring [2010]": datetime(2010, 4, 1), - "Modern - Summer [2010]": datetime(2010, 6, 1), - "Modern - Fall [2010]": datetime(2010, 10, 1), - "Georgian War [2008]": datetime(2008, 8, 7), - "Syrian War [2011]": datetime(2011, 3, 15), - "6 days war [1967]": datetime(1967, 6, 5), - "Yom Kippour War [1973]": datetime(1973, 10, 6), - "First Lebanon War [1982]": datetime(1982, 6, 6), - "Arab-Israeli War [1948]": datetime(1948, 5, 15), -} - - -def wrap_label_text(text: str, width: int = 100) -> str: - return "
    ".join(textwrap.wrap(text, width=width)) - - -class NewGameWizard(QtWidgets.QWizard): - def __init__(self, parent=None): - super(NewGameWizard, self).__init__(parent) - self.setModal(True) - - # The wizard should probably be refactored to edit this directly, but for now we - # just create a Settings object so that we can load the player's preserved - # defaults. We'll recreate a new settings and merge in the wizard options later. - default_settings = Settings() - default_settings.merge_player_settings() - - mod_settings = ModSettings() - mod_settings.merge_player_settings() - - self.lua_plugin_manager = LuaPluginManager.load() - self.lua_plugin_manager.merge_player_settings() - - factions = Factions.load() - - self.campaigns = list(sorted(Campaign.load_each(), key=lambda x: x.name)) - - self.faction_selection_page = FactionSelection(factions) - self.addPage(IntroPage()) - self.theater_page = TheaterConfiguration( - self.campaigns, self.faction_selection_page - ) - self.addPage(self.theater_page) - self.addPage(self.faction_selection_page) - self.addPage(GeneratorOptions(default_settings, mod_settings)) - self.difficulty_page = DifficultyAndAutomationOptions( - default_settings, self.theater_page.campaignList.selected_campaign - ) - self.plugins_page = PluginsPage(self.lua_plugin_manager) - - # Update difficulty page on campaign select - self.theater_page.campaign_selected.connect( - lambda c: self.difficulty_page.set_campaign_values(c) - ) - self.addPage(self.difficulty_page) - self.addPage(self.plugins_page) - self.addPage(ConclusionPage()) - - self.setPixmap( - QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap("./resources/ui/wizard/watermark1.png"), - ) - self.setWizardStyle(QtWidgets.QWizard.ModernStyle) - - self.setWindowTitle("New Game") - - def accept(self): - logging.info("New Game Wizard accept") - logging.info("======================") - - campaign = self.field("selectedCampaign") - if campaign is None: - campaign = self.theater_page.campaignList.selected_campaign - if campaign is None: - campaign = self.campaigns[0] - - logging.info("New campaign selected: %s", campaign.name) - - if self.field("usePreset"): - start_date = TIME_PERIODS[ - list(TIME_PERIODS.keys())[self.field("timePeriod")] - ] - else: - start_date = self.theater_page.calendar.selectedDate().toPython() - - self.lua_plugin_manager.save_player_settings() - - logging.info("New campaign start date: %s", start_date.strftime("%m/%d/%Y")) - settings = Settings( - player_income_multiplier=self.field("player_income_multiplier") / 10, - enemy_income_multiplier=self.field("enemy_income_multiplier") / 10, - automate_runway_repair=self.field("automate_runway_repairs"), - automate_front_line_reinforcements=self.field( - "automate_front_line_purchases" - ), - desired_player_mission_duration=timedelta( - minutes=self.field("desired_player_mission_duration") - ), - automate_aircraft_reinforcements=self.field("automate_aircraft_purchases"), - supercarrier=self.field("supercarrier"), - ) - settings.save_player_settings() - generator_settings = GeneratorSettings( - start_date=start_date, - start_time=campaign.recommended_start_time, - player_budget=int(self.field("starting_money")), - enemy_budget=int(self.field("enemy_starting_money")), - # QSlider forces integers, so we use 1 to 50 and divide by 10 to - # give 0.1 to 5.0. - inverted=self.field("invertMap"), - advanced_iads=self.field("advanced_iads"), - no_carrier=self.field("no_carrier"), - no_lha=self.field("no_lha"), - no_player_navy=self.field("no_player_navy"), - no_enemy_navy=self.field("no_enemy_navy"), - ) - mod_settings = ModSettings( - a4_skyhawk=self.field("a4_skyhawk"), - f22_raptor=self.field("f22_raptor"), - f104_starfighter=self.field("f104_starfighter"), - f4_phantom=self.field("f4_phantom"), - hercules=self.field("hercules"), - uh_60l=self.field("uh_60l"), - jas39_gripen=self.field("jas39_gripen"), - su57_felon=self.field("su57_felon"), - ov10a_bronco=self.field("ov10a_bronco"), - frenchpack=self.field("frenchpack"), - high_digit_sams=self.field("high_digit_sams"), - fa18efg=self.field("fa18efg"), - ) - mod_settings.save_player_settings() - - blue_faction = self.faction_selection_page.selected_blue_faction - red_faction = self.faction_selection_page.selected_red_faction - - logging.info("New campaign blue faction: %s", blue_faction.name) - logging.info("New campaign red faction: %s", red_faction.name) - - theater = campaign.load_theater(generator_settings.advanced_iads) - - logging.info("New campaign theater: %s", theater.terrain.name) - - generator = GameGenerator( - blue_faction, - red_faction, - theater, - campaign.load_air_wing_config(theater), - settings, - generator_settings, - mod_settings, - self.lua_plugin_manager, - ) - game = generator.generate() - - if AirWingConfigurationDialog(game, self).exec() == QDialog.DialogCode.Rejected: - logging.info("Aborted air wing configuration") - return - - game.begin_turn_0() - GameUpdateSignal.get_instance().game_generated.emit(game) - - super(NewGameWizard, self).accept() - - -class IntroPage(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super(IntroPage, self).__init__(parent) - - self.setTitle("Introduction") - self.setPixmap( - QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap("./resources/ui/wizard/watermark1.png"), - ) - - label = QtWidgets.QLabel( - "This wizard will help you setup a new game.\n\n" - "Please make sure you saved and backed up your previous game before going through." - ) - label.setWordWrap(True) - - layout = QtWidgets.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - - -class FactionSelection(QtWidgets.QWizardPage): - def __init__(self, factions: Factions, parent=None) -> None: - super().__init__(parent) - - self.factions = factions - - self.setTitle("Faction selection") - self.setSubTitle( - "\nChoose the two opposing factions and select the player side." - ) - self.setPixmap( - QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap("./resources/ui/misc/generator.png"), - ) - - self.setMinimumHeight(250) - - # Factions selection - self.factionsGroup = QtWidgets.QGroupBox("Factions") - self.factionsGroupLayout = QtWidgets.QHBoxLayout() - self.blueGroupLayout = QtWidgets.QGridLayout() - self.redGroupLayout = QtWidgets.QGridLayout() - - blueFaction = QtWidgets.QLabel("Player Faction :") - self.blueFactionSelect = QtWidgets.QComboBox() - for f in self.factions.iter_faction_names(): - self.blueFactionSelect.addItem(f) - blueFaction.setBuddy(self.blueFactionSelect) - - redFaction = QtWidgets.QLabel("Enemy Faction :") - self.redFactionSelect = QtWidgets.QComboBox() - redFaction.setBuddy(self.redFactionSelect) - - # Faction description - self.blueFactionDescription = QTextEdit("") - self.blueFactionDescription.setReadOnly(True) - - self.redFactionDescription = QTextEdit("") - self.redFactionDescription.setReadOnly(True) - - # Setup default selected factions - for i, r in enumerate(self.factions.iter_faction_names()): - self.redFactionSelect.addItem(r) - if r == "Russia 1990": - self.redFactionSelect.setCurrentIndex(i) - if r == "USA 2005": - self.blueFactionSelect.setCurrentIndex(i) - - self.blueGroupLayout.addWidget(blueFaction, 0, 0) - self.blueGroupLayout.addWidget(self.blueFactionSelect, 0, 1) - self.blueGroupLayout.addWidget(self.blueFactionDescription, 1, 0, 1, 2) - - self.redGroupLayout.addWidget(redFaction, 0, 0) - self.redGroupLayout.addWidget(self.redFactionSelect, 0, 1) - self.redGroupLayout.addWidget(self.redFactionDescription, 1, 0, 1, 2) - - self.factionsGroupLayout.addLayout(self.blueGroupLayout) - self.factionsGroupLayout.addLayout(self.redGroupLayout) - self.factionsGroup.setLayout(self.factionsGroupLayout) - - # Docs Link - docsText = QtWidgets.QLabel( - 'How to create your own faction' - ) - docsText.setAlignment(Qt.AlignCenter) - docsText.setOpenExternalLinks(True) - - # Link form fields - self.registerField("blueFaction", self.blueFactionSelect) - self.registerField("redFaction", self.redFactionSelect) - - # Build layout - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.factionsGroup) - layout.addWidget(docsText) - self.setLayout(layout) - self.updateUnitRecap() - - self.blueFactionSelect.activated.connect(self.updateUnitRecap) - self.redFactionSelect.activated.connect(self.updateUnitRecap) - - def setDefaultFactions(self, campaign: Campaign): - """Set default faction for selected campaign""" - - self.blueFactionSelect.clear() - self.redFactionSelect.clear() - - self.factions.reset_campaign_defined() - campaign.register_campaign_specific_factions(self.factions) - - for name in self.factions.iter_faction_names(): - self.blueFactionSelect.addItem(name) - self.redFactionSelect.addItem(name) - - self.blueFactionSelect.setCurrentText(campaign.recommended_player_faction.name) - self.redFactionSelect.setCurrentText(campaign.recommended_enemy_faction.name) - - self.updateUnitRecap() - - def cleanupPage(self): - """When clicking Back button, reset factions to campaign defaults""" - self.setDefaultFactions(self.field("selectedCampaign")) - - def updateUnitRecap(self): - red_faction = self.factions.get_by_name(self.redFactionSelect.currentText()) - blue_faction = self.factions.get_by_name(self.blueFactionSelect.currentText()) - - template = jinja_env.get_template("factiontemplate_EN.j2") - - blue_faction_txt = template.render({"faction": blue_faction}) - red_faction_txt = template.render({"faction": red_faction}) - - self.blueFactionDescription.setText(blue_faction_txt) - self.redFactionDescription.setText(red_faction_txt) - - @property - def selected_blue_faction(self) -> Faction: - return self.factions.get_by_name(self.blueFactionSelect.currentText()) - - @property - def selected_red_faction(self) -> Faction: - return self.factions.get_by_name(self.redFactionSelect.currentText()) - - -class TheaterConfiguration(QtWidgets.QWizardPage): - campaign_selected = Signal(Campaign) - - def __init__( - self, - campaigns: List[Campaign], - faction_selection: FactionSelection, - parent=None, - ) -> None: - super().__init__(parent) - - self.faction_selection = faction_selection - - self.setTitle("Theater configuration") - self.setSubTitle("\nChoose a terrain and time period for this game.") - self.setPixmap( - QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap("./resources/ui/wizard/logo1.png"), - ) - - self.setPixmap( - QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap("./resources/ui/wizard/watermark3.png"), - ) - - # List of campaigns - show_incompatible_campaigns_checkbox = QCheckBox( - text="Show incompatible campaigns" - ) - show_incompatible_campaigns_checkbox.setChecked(False) - self.campaignList = QCampaignList( - campaigns, show_incompatible_campaigns_checkbox.isChecked() - ) - show_incompatible_campaigns_checkbox.toggled.connect( - lambda checked: self.campaignList.setup_content(show_incompatible=checked) - ) - self.registerField("selectedCampaign", self.campaignList) - - # Faction description - self.campaignMapDescription = QTextEdit("") - self.campaignMapDescription.setReadOnly(True) - self.campaignMapDescription.setMaximumHeight(200) - - self.performanceText = QTextEdit("") - self.performanceText.setReadOnly(True) - self.performanceText.setMaximumHeight(90) - - # Campaign settings - mapSettingsGroup = QtWidgets.QGroupBox("Map Settings") - mapSettingsLayout = QtWidgets.QGridLayout() - invertMap = QtWidgets.QCheckBox() - self.registerField("invertMap", invertMap) - mapSettingsLayout.addWidget(QtWidgets.QLabel("Invert Map"), 0, 0) - mapSettingsLayout.addWidget(invertMap, 0, 1) - self.advanced_iads = QtWidgets.QCheckBox() - self.registerField("advanced_iads", self.advanced_iads) - self.iads_label = QtWidgets.QLabel("Advanced IADS (WIP)") - mapSettingsLayout.addWidget(self.iads_label, 1, 0) - mapSettingsLayout.addWidget(self.advanced_iads, 1, 1) - mapSettingsGroup.setLayout(mapSettingsLayout) - - # Time Period - timeGroup = QtWidgets.QGroupBox("Time Period") - timePeriod = QtWidgets.QLabel("Start date :") - timePeriodSelect = QtWidgets.QComboBox() - timePeriodPresetLabel = QLabel("Use preset :") - timePeriodPreset = QtWidgets.QCheckBox() - timePeriodPreset.setChecked(True) - self.calendar = QLiberationCalendar() - self.calendar.setSelectedDate(QDate()) - self.calendar.setDisabled(True) - - def onTimePeriodChanged(): - self.calendar.setSelectedDate( - list(TIME_PERIODS.values())[timePeriodSelect.currentIndex()] - ) - - timePeriodSelect.currentTextChanged.connect(onTimePeriodChanged) - - for r in TIME_PERIODS: - timePeriodSelect.addItem(r) - timePeriod.setBuddy(timePeriodSelect) - timePeriodSelect.setCurrentIndex(21) - - def onTimePeriodCheckboxChanged(): - if timePeriodPreset.isChecked(): - self.calendar.setDisabled(True) - timePeriodSelect.setDisabled(False) - onTimePeriodChanged() - else: - self.calendar.setDisabled(False) - timePeriodSelect.setDisabled(True) - - timePeriodPreset.stateChanged.connect(onTimePeriodCheckboxChanged) - - # Bind selection method for campaign selection - def on_campaign_selected(): - template = jinja_env.get_template("campaigntemplate_EN.j2") - template_perf = jinja_env.get_template( - "campaign_performance_template_EN.j2" - ) - campaign = self.campaignList.selected_campaign - self.setField("selectedCampaign", campaign) - if campaign is None: - self.campaignMapDescription.setText("No campaign selected") - self.performanceText.setText("No campaign selected") - return - - self.campaignMapDescription.setText(template.render({"campaign": campaign})) - self.faction_selection.setDefaultFactions(campaign) - self.performanceText.setText( - template_perf.render({"performance": campaign.performance}) - ) - - if (start_date := campaign.recommended_start_date) is not None: - self.calendar.setSelectedDate( - QDate(start_date.year, start_date.month, start_date.day) - ) - timePeriodPreset.setChecked(False) - else: - timePeriodPreset.setChecked(True) - self.advanced_iads.setEnabled(campaign.advanced_iads) - self.iads_label.setEnabled(campaign.advanced_iads) - self.advanced_iads.setChecked(campaign.advanced_iads) - if not campaign.advanced_iads: - self.advanced_iads.setToolTip( - "Advanced IADS is not supported by this campaign" - ) - else: - self.advanced_iads.setToolTip("Enable Advanced IADS") - - self.campaign_selected.emit(campaign) - - self.campaignList.selectionModel().setCurrentIndex( - self.campaignList.indexAt(QPoint(1, 1)), QItemSelectionModel.Rows - ) - - self.campaignList.selectionModel().selectionChanged.connect( - on_campaign_selected - ) - on_campaign_selected() - - docsText = QtWidgets.QLabel( - "

    Want more campaigns? You can " - 'offer to help, ' - 'play a community campaign, ' - 'or create your own.' - "

    " - ) - docsText.setAlignment(Qt.AlignCenter) - docsText.setOpenExternalLinks(True) - - # Register fields - self.registerField("timePeriod", timePeriodSelect) - self.registerField("usePreset", timePeriodPreset) - - timeGroupLayout = QtWidgets.QGridLayout() - timeGroupLayout.addWidget(timePeriodPresetLabel, 0, 0) - timeGroupLayout.addWidget(timePeriodPreset, 0, 1) - timeGroupLayout.addWidget(timePeriod, 1, 0) - timeGroupLayout.addWidget(timePeriodSelect, 1, 1) - timeGroupLayout.addWidget(self.calendar, 0, 2, 3, 1) - timeGroup.setLayout(timeGroupLayout) - - layout = QtWidgets.QGridLayout() - layout.setColumnMinimumWidth(0, 20) - layout.addWidget(self.campaignList, 0, 0, 5, 1) - layout.addWidget(show_incompatible_campaigns_checkbox, 5, 0, 1, 1) - layout.addWidget(docsText, 6, 0, 1, 1) - layout.addWidget(self.campaignMapDescription, 0, 1, 1, 1) - layout.addWidget(self.performanceText, 1, 1, 1, 1) - layout.addWidget(mapSettingsGroup, 2, 1, 1, 1) - layout.addWidget(timeGroup, 3, 1, 3, 1) - self.setLayout(layout) - - def initializePage(self): - """Ensure that selectCampaign field is set after user clicks Back to previous page and Next back onto this page""" - campaign = self.campaignList.selected_campaign - self.setField("selectedCampaign", campaign) - - -class BudgetInputs(QtWidgets.QGridLayout): - def __init__(self, label: str, value: int) -> None: - super().__init__() - self.addWidget(QtWidgets.QLabel(label), 0, 0) - - minimum = 0 - maximum = 5000 - - slider = QtWidgets.QSlider(Qt.Horizontal) - slider.setMinimum(minimum) - slider.setMaximum(maximum) - slider.setValue(value) - self.starting_money = CurrencySpinner(minimum, maximum, value) - slider.valueChanged.connect(lambda x: self.starting_money.setValue(x)) - self.starting_money.valueChanged.connect(lambda x: slider.setValue(x)) - - self.addWidget(slider, 1, 0) - self.addWidget(self.starting_money, 1, 1) - - -class DifficultyAndAutomationOptions(QtWidgets.QWizardPage): - def __init__( - self, default_settings: Settings, current_campaign: Campaign | None, parent=None - ) -> None: - super().__init__(parent) - - self.setTitle("Difficulty and automation options") - self.setSubTitle( - "\nOptions controlling game difficulty and level of " "player involvement." - ) - self.setPixmap( - QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap("./resources/ui/wizard/logo1.png"), - ) - - layout = QtWidgets.QVBoxLayout() - - economy_group = QtWidgets.QGroupBox("Economy options") - layout.addWidget(economy_group) - economy_layout = QtWidgets.QVBoxLayout() - economy_group.setLayout(economy_layout) - - economy_layout.addWidget(QLabel("Player income multiplier")) - self.player_income = FloatSpinSlider(0, 5, 1, divisor=10) - self.registerField("player_income_multiplier", self.player_income.spinner) - economy_layout.addLayout(self.player_income) - - economy_layout.addWidget(QLabel("Enemy income multiplier")) - self.enemy_income = FloatSpinSlider(0, 5, 1, divisor=10) - self.registerField("enemy_income_multiplier", self.enemy_income.spinner) - economy_layout.addLayout(self.enemy_income) - - self.player_budget = BudgetInputs("Player starting budget", DEFAULT_BUDGET) - self.registerField("starting_money", self.player_budget.starting_money) - economy_layout.addLayout(self.player_budget) - - self.enemy_budget = BudgetInputs("Enemy starting budget", DEFAULT_BUDGET) - self.registerField("enemy_starting_money", self.enemy_budget.starting_money) - economy_layout.addLayout(self.enemy_budget) - - assist_group = QtWidgets.QGroupBox("Player assists") - layout.addWidget(assist_group) - assist_layout = QtWidgets.QGridLayout() - assist_group.setLayout(assist_layout) - - assist_layout.addWidget(QtWidgets.QLabel("Automate runway repairs"), 0, 0) - runway_repairs = QtWidgets.QCheckBox() - runway_repairs.setChecked(default_settings.automate_runway_repair) - self.registerField("automate_runway_repairs", runway_repairs) - assist_layout.addWidget(runway_repairs, 0, 1, Qt.AlignRight) - - assist_layout.addWidget(QtWidgets.QLabel("Automate front-line purchases"), 1, 0) - front_line = QtWidgets.QCheckBox() - front_line.setChecked(default_settings.automate_front_line_reinforcements) - self.registerField("automate_front_line_purchases", front_line) - assist_layout.addWidget(front_line, 1, 1, Qt.AlignRight) - - assist_layout.addWidget(QtWidgets.QLabel("Automate aircraft purchases"), 2, 0) - aircraft = QtWidgets.QCheckBox() - aircraft.setChecked(default_settings.automate_aircraft_reinforcements) - self.registerField("automate_aircraft_purchases", aircraft) - assist_layout.addWidget(aircraft, 2, 1, Qt.AlignRight) - - self.setLayout(layout) - - def set_campaign_values(self, campaign: Campaign) -> None: - self.player_budget.starting_money.setValue(campaign.recommended_player_money) - self.enemy_budget.starting_money.setValue(campaign.recommended_enemy_money) - self.player_income.spinner.setValue( - int(campaign.recommended_player_income_multiplier * 10) - ) - self.enemy_income.spinner.setValue( - int(campaign.recommended_enemy_income_multiplier * 10) - ) - - -class PluginOptionCheckbox(QCheckBox): - def __init__(self, option: LuaPluginOption) -> None: - super().__init__(option.name) - self.option = option - self.setChecked(self.option.enabled) - self.toggled.connect(self.on_toggle) - - def on_toggle(self, enabled: bool) -> None: - self.option.enabled = enabled - - -class PluginGroupBox(QtWidgets.QGroupBox): - def __init__(self, plugin: LuaPlugin) -> None: - super().__init__(plugin.name) - self.plugin = plugin - - self.setCheckable(True) - self.setChecked(self.plugin.enabled) - self.toggled.connect(self.on_toggle) - - layout = QVBoxLayout() - self.setLayout(layout) - - self.checkboxes = [] - for option in self.plugin.options: - checkbox = PluginOptionCheckbox(option) - checkbox.setEnabled(self.plugin.enabled) - layout.addWidget(checkbox) - self.checkboxes.append(checkbox) - - if not self.plugin.options: - layout.addWidget(QLabel("Plugin has no settings.")) - - def on_toggle(self, enabled: bool) -> None: - self.plugin.enabled = enabled - for checkbox in self.checkboxes: - checkbox.setEnabled(enabled) - - -class PluginsPage(QtWidgets.QWizardPage): - def __init__(self, lua_plugins_manager: LuaPluginManager, parent=None) -> None: - super().__init__(parent) - self.lua_plugins_manager = lua_plugins_manager - - self.setTitle("Plugins") - self.setSubTitle("Enable plugins with the checkbox next to their name") - self.setPixmap( - QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap("./resources/ui/wizard/logo1.png"), - ) - - main_layout = QVBoxLayout() - self.setLayout(main_layout) - - scroll_content = QWidget() - layout = QVBoxLayout() - scroll_content.setLayout(layout) - scroll = QScrollArea() - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - main_layout.addWidget(scroll) - - self.group_boxes = [] - for plugin in self.lua_plugins_manager.iter_plugins(): - if plugin.show_in_ui: - group_box = PluginGroupBox(plugin) - layout.addWidget(group_box) - self.group_boxes.append(group_box) - - -class GeneratorOptions(QtWidgets.QWizardPage): - def __init__( - self, default_settings: Settings, mod_settings: ModSettings, parent=None - ) -> None: - super().__init__(parent) - self.setTitle("Generator settings") - self.setSubTitle("\nOptions affecting the generation of the game.") - self.setPixmap( - QtWidgets.QWizard.LogoPixmap, - QtGui.QPixmap("./resources/ui/wizard/logo1.png"), - ) - - # Campaign settings - generatorSettingsGroup = QtWidgets.QGroupBox("Generator Settings") - no_carrier = QtWidgets.QCheckBox() - self.registerField("no_carrier", no_carrier) - no_lha = QtWidgets.QCheckBox() - self.registerField("no_lha", no_lha) - supercarrier = QtWidgets.QCheckBox() - supercarrier.setChecked(default_settings.supercarrier) - self.registerField("supercarrier", supercarrier) - no_player_navy = QtWidgets.QCheckBox() - self.registerField("no_player_navy", no_player_navy) - no_enemy_navy = QtWidgets.QCheckBox() - self.registerField("no_enemy_navy", no_enemy_navy) - desired_player_mission_duration = TimeInputs( - default_settings.desired_player_mission_duration, minimum=30, maximum=150 - ) - self.registerField( - "desired_player_mission_duration", desired_player_mission_duration.spinner - ) - - generatorLayout = QtWidgets.QGridLayout() - generatorLayout.addWidget(QtWidgets.QLabel("No Aircraft Carriers"), 1, 0) - generatorLayout.addWidget(no_carrier, 1, 1) - generatorLayout.addWidget(QtWidgets.QLabel("No LHA"), 2, 0) - generatorLayout.addWidget(no_lha, 2, 1) - generatorLayout.addWidget(QtWidgets.QLabel("Use Supercarrier module"), 3, 0) - generatorLayout.addWidget(supercarrier, 3, 1) - generatorLayout.addWidget(QtWidgets.QLabel("No Player Navy"), 4, 0) - generatorLayout.addWidget(no_player_navy, 4, 1) - generatorLayout.addWidget(QtWidgets.QLabel("No Enemy Navy"), 5, 0) - generatorLayout.addWidget(no_enemy_navy, 5, 1) - generatorLayout.addWidget(QtWidgets.QLabel("Desired mission duration"), 6, 0) - generatorLayout.addLayout(desired_player_mission_duration, 7, 0) - generatorSettingsGroup.setLayout(generatorLayout) - - modSettingsGroup = QtWidgets.QGroupBox("Mod Settings") - - a4_skyhawk = QtWidgets.QCheckBox() - a4_skyhawk.setChecked(mod_settings.a4_skyhawk) - self.registerField("a4_skyhawk", a4_skyhawk) - - hercules = QtWidgets.QCheckBox() - hercules.setChecked(mod_settings.hercules) - self.registerField("hercules", hercules) - - uh_60l = QtWidgets.QCheckBox() - uh_60l.setChecked(mod_settings.uh_60l) - self.registerField("uh_60l", uh_60l) - - f22_raptor = QtWidgets.QCheckBox() - f22_raptor.setChecked(mod_settings.f22_raptor) - self.registerField("f22_raptor", f22_raptor) - - f104_starfighter = QtWidgets.QCheckBox() - f104_starfighter.setChecked(mod_settings.f104_starfighter) - self.registerField("f104_starfighter", f104_starfighter) - - f4_phantom = QtWidgets.QCheckBox() - f4_phantom.setChecked(mod_settings.f4_phantom) - self.registerField("f4_phantom", f4_phantom) - - jas39_gripen = QtWidgets.QCheckBox() - jas39_gripen.setChecked(mod_settings.jas39_gripen) - self.registerField("jas39_gripen", jas39_gripen) - - su57_felon = QtWidgets.QCheckBox() - su57_felon.setChecked(mod_settings.su57_felon) - self.registerField("su57_felon", su57_felon) - - ov10a_bronco = QtWidgets.QCheckBox() - ov10a_bronco.setChecked(mod_settings.ov10a_bronco) - self.registerField("ov10a_bronco", ov10a_bronco) - - frenchpack = QtWidgets.QCheckBox() - frenchpack.setChecked(mod_settings.frenchpack) - self.registerField("frenchpack", frenchpack) - - high_digit_sams = QtWidgets.QCheckBox() - high_digit_sams.setChecked(mod_settings.high_digit_sams) - self.registerField("high_digit_sams", high_digit_sams) - - fa18efg = QtWidgets.QCheckBox() - fa18efg.setChecked(mod_settings.fa18efg) - self.registerField("fa18efg", fa18efg) - - modHelpText = QtWidgets.QLabel( - "

    Select the mods you have installed. If your chosen factions support them, you'll be able to use these mods in your campaign.

    " - ) - modHelpText.setAlignment(Qt.AlignCenter) - - modLayout = QtWidgets.QGridLayout() - modLayout_row = 1 - modLayout.addWidget( - QtWidgets.QLabel("A-4E Skyhawk (version 2.2.0)"), modLayout_row, 0 - ) - modLayout.addWidget(a4_skyhawk, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("F-22A Raptor"), modLayout_row, 0) - modLayout.addWidget(f22_raptor, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("F-104 Starfighter"), modLayout_row, 0) - modLayout.addWidget(f104_starfighter, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("F-4B&C Phantom"), modLayout_row, 0) - modLayout.addWidget(f4_phantom, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget( - QtWidgets.QLabel("C-130J-30 Super Hercules"), modLayout_row, 0 - ) - modLayout.addWidget(hercules, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget( - QtWidgets.QLabel("UH-60L Black Hawk (version 1.3.1)"), modLayout_row, 0 - ) - modLayout.addWidget(uh_60l, modLayout_row, 1) - modLayout_row += 1 - # Section break here for readability - modLayout.addWidget(QtWidgets.QWidget(), modLayout_row, 0) - modLayout_row += 1 - modLayout.addWidget( - QtWidgets.QLabel("JAS 39 Gripen (version v1.8.0-beta)"), modLayout_row, 0 - ) - modLayout.addWidget(jas39_gripen, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("Su-57 Felon"), modLayout_row, 0) - modLayout.addWidget(su57_felon, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("OV-10A Bronco"), modLayout_row, 0) - modLayout.addWidget(ov10a_bronco, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("Frenchpack"), modLayout_row, 0) - modLayout.addWidget(frenchpack, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("High Digit SAMs"), modLayout_row, 0) - modLayout.addWidget(high_digit_sams, modLayout_row, 1) - modLayout_row += 1 - modLayout.addWidget(QtWidgets.QLabel("fa18efg"), modLayout_row, 0) - modLayout.addWidget(fa18efg, modLayout_row, 1) - modSettingsGroup.setLayout(modLayout) - modLayout_row += 1 - - mlayout = QVBoxLayout() - mlayout.addWidget(generatorSettingsGroup) - mlayout.addWidget(modSettingsGroup) - mlayout.addWidget(modHelpText) - self.setLayout(mlayout) - - -class ConclusionPage(QtWidgets.QWizardPage): - def __init__(self, parent=None): - super(ConclusionPage, self).__init__(parent) - - self.setTitle("Conclusion") - self.setSubTitle("\n\n") - self.setPixmap( - QtWidgets.QWizard.WatermarkPixmap, - QtGui.QPixmap("./resources/ui/wizard/watermark2.png"), - ) - - self.label = QtWidgets.QLabel( - "Click 'Finish' to generate and start the new game." - ) - self.label.setWordWrap(True) - - layout = QtWidgets.QVBoxLayout() - layout.addWidget(self.label) - self.setLayout(layout) diff --git a/qt_ui/windows/notes/QNotesWindow.py b/qt_ui/windows/notes/QNotesWindow.py deleted file mode 100644 index 4fa7e08c9..000000000 --- a/qt_ui/windows/notes/QNotesWindow.py +++ /dev/null @@ -1,67 +0,0 @@ -from PySide6.QtWidgets import ( - QDialog, - QPlainTextEdit, - QVBoxLayout, - QHBoxLayout, - QPushButton, - QLabel, -) -from PySide6.QtGui import QTextCursor -from PySide6.QtCore import QTimer - -import qt_ui.uiconstants as CONST -from game.game import Game - -from time import sleep - - -class QNotesWindow(QDialog): - def __init__(self, game: Game): - super(QNotesWindow, self).__init__() - - self.game = game - self.setWindowTitle("Notes") - self.setWindowIcon(CONST.ICONS["Notes"]) - self.setMinimumSize(400, 100) - self.resize(600, 450) - - self.vbox = QVBoxLayout() - self.setLayout(self.vbox) - - self.vbox.addWidget( - QLabel("Saved notes are available as a page in your kneeboard.") - ) - - self.textbox = QPlainTextEdit(self) - try: - self.textbox.setPlainText(self.game.notes) - self.textbox.moveCursor(QTextCursor.End) - except AttributeError: # old save may not have game.notes - pass - self.textbox.move(10, 10) - self.textbox.resize(600, 450) - self.textbox.setStyleSheet("background: #1D2731;") - self.vbox.addWidget(self.textbox) - - self.button_row = QHBoxLayout() - self.vbox.addLayout(self.button_row) - - self.clear_button = QPushButton(self) - self.clear_button.setText("CLEAR") - self.clear_button.setProperty("style", "btn-primary") - self.clear_button.clicked.connect(self.clearNotes) - self.button_row.addWidget(self.clear_button) - - self.save_button = QPushButton(self) - self.save_button.setText("SAVE") - self.save_button.setProperty("style", "btn-success") - self.save_button.clicked.connect(self.saveNotes) - self.button_row.addWidget(self.save_button) - - def clearNotes(self) -> None: - self.textbox.setPlainText("") - - def saveNotes(self) -> None: - self.game.notes = self.textbox.toPlainText() - self.save_button.setText("SAVED") - QTimer.singleShot(5000, lambda: self.save_button.setText("SAVE")) diff --git a/qt_ui/windows/preferences/QLiberationFirstStartWindow.py b/qt_ui/windows/preferences/QLiberationFirstStartWindow.py deleted file mode 100644 index 58b255ce2..000000000 --- a/qt_ui/windows/preferences/QLiberationFirstStartWindow.py +++ /dev/null @@ -1,91 +0,0 @@ -from PySide6.QtGui import QIcon, Qt -from PySide6.QtWidgets import ( - QDialog, - QVBoxLayout, - QPushButton, - QHBoxLayout, - QPlainTextEdit, - QTextEdit, -) - -from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences - - -class QLiberationFirstStartWindow(QDialog): - def __init__(self): - super(QLiberationFirstStartWindow, self).__init__() - - self.setModal(True) - self.setWindowTitle("First start configuration") - self.setMinimumSize(500, 200) - self.setWindowIcon(QIcon("./resources/icon.png")) - self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Dialog | Qt.WindowTitleHint) - self.setWindowModality(Qt.WindowModal) - self.preferences = QLiberationPreferences() - - WARN_TEXT = """ - Welcome to DCS Liberation ! -

    - Please take 30 seconds to read this : - -

    DCS Liberation will modify this file in your DCS installation directory :

    -
    - <dcs_installation_directory>/Scripts/MissionScripting.lua
    - -

    - This will disable some security limits of the DCS World Lua scripting environment, in order to allow communication between DCS World and DCS Liberation. - However, the modification of this file could potentially grant access to your filesystem to malicious DCS mission files. -

    - -

    So, you should not join untrusted servers or open untrusted mission files within DCS world while DCS Liberation is running.

    - -

    - DCS Liberation will restore your original MissionScripting file when it close. -

    - -

    - However, should DCS Liberation encounter an unexpected crash (which should not happen), the MissionScripting file might not be restored. - If that occurs, you can use the backup file saved in the DCS Liberation directory there : -

    - -
    - ./resources/scripts/MissionScripting.original.lua
    - -

    Then copy it in your DCS installation directory to replace this file :

    - -
    - <dcs_installation_directory>/Scripts/MissionScripting.lua
    - -

    As you click on the button below, the file will be replaced in your DCS installation directory.

    - -
    -

    If you leave the DCS Installation Directory empty, DCS Liberation can not automatically replace the MissionScripting.lua and will therefore not work correctly! - In this case, you need to edit the file yourself. The easiest way to do it is to replace the original file with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua). -

    You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

    - - -

    - - Thank you for reading ! - """ - self.warning_text = QTextEdit(WARN_TEXT) - self.warning_text.setReadOnly(True) - self.apply_button = QPushButton("I have read everything and I Accept") - self.apply_button.clicked.connect(lambda: self.apply()) - self.initUI() - - def initUI(self): - layout = QVBoxLayout() - layout.addWidget(self.preferences) - layout.addWidget(self.warning_text) - layout.addStretch() - apply_btn_layout = QHBoxLayout() - apply_btn_layout.addStretch() - apply_btn_layout.addWidget(self.apply_button) - layout.addLayout(apply_btn_layout) - self.setLayout(layout) - - def apply(self): - print("Applying changes") - if self.preferences.apply(): - self.close() diff --git a/qt_ui/windows/preferences/QLiberationPreferences.py b/qt_ui/windows/preferences/QLiberationPreferences.py deleted file mode 100644 index 89374f350..000000000 --- a/qt_ui/windows/preferences/QLiberationPreferences.py +++ /dev/null @@ -1,151 +0,0 @@ -import os - -from PySide6.QtGui import Qt -from PySide6.QtWidgets import ( - QComboBox, - QFileDialog, - QFrame, - QGridLayout, - QLabel, - QLineEdit, - QMessageBox, - QPushButton, - QVBoxLayout, -) - -from qt_ui import liberation_install, liberation_theme -from qt_ui.liberation_theme import THEMES, get_theme_index, set_theme_index - - -class QLiberationPreferences(QFrame): - def __init__(self): - super(QLiberationPreferences, self).__init__() - self.saved_game_dir = "" - self.dcs_install_dir = "" - self.install_dir_ignore_warning = False - - self.dcs_install_dir = liberation_install.get_dcs_install_directory() - self.saved_game_dir = liberation_install.get_saved_game_dir() - - self.edit_dcs_install_dir = QLineEdit(self.dcs_install_dir) - self.edit_saved_game_dir = QLineEdit(self.saved_game_dir) - - self.edit_dcs_install_dir.setMinimumWidth(300) - self.edit_saved_game_dir.setMinimumWidth(300) - - self.browse_saved_game = QPushButton("Browse...") - self.browse_saved_game.clicked.connect(self.on_browse_saved_games) - self.browse_install_dir = QPushButton("Browse...") - self.browse_install_dir.clicked.connect(self.on_browse_installation_dir) - self.themeSelect = QComboBox() - [self.themeSelect.addItem(y["themeName"]) for x, y in THEMES.items()] - - self.initUi() - - def initUi(self): - main_layout = QVBoxLayout() - layout = QGridLayout() - layout.addWidget( - QLabel("DCS saved game directory:"), - 0, - 0, - alignment=Qt.AlignLeft, - ) - layout.addWidget(self.edit_saved_game_dir, 1, 0, alignment=Qt.AlignRight) - layout.addWidget(self.browse_saved_game, 1, 1, alignment=Qt.AlignRight) - layout.addWidget( - QLabel("DCS installation directory:"), - 2, - 0, - alignment=Qt.AlignLeft, - ) - layout.addWidget(self.edit_dcs_install_dir, 3, 0, alignment=Qt.AlignRight) - layout.addWidget(self.browse_install_dir, 3, 1, alignment=Qt.AlignRight) - layout.addWidget(QLabel("Theme (Requires Restart)"), 4, 0) - layout.addWidget(self.themeSelect, 4, 1, alignment=Qt.AlignRight) - self.themeSelect.setCurrentIndex(get_theme_index()) - - main_layout.addLayout(layout) - main_layout.addStretch() - - self.setLayout(main_layout) - - def on_browse_saved_games(self): - saved_game_dir = str( - QFileDialog.getExistingDirectory(self, "Select DCS Saved Game Directory") - ) - if saved_game_dir: - self.saved_game_dir = saved_game_dir - self.edit_saved_game_dir.setText(saved_game_dir) - - def on_browse_installation_dir(self): - install_dir = str( - QFileDialog.getExistingDirectory(self, "Select DCS Installation Directory") - ) - if install_dir: - self.dcs_install_dir = install_dir - self.edit_dcs_install_dir.setText(install_dir) - - def apply(self): - print("Applying changes") - self.saved_game_dir = self.edit_saved_game_dir.text() - self.dcs_install_dir = self.edit_dcs_install_dir.text() - set_theme_index(self.themeSelect.currentIndex()) - - if not os.path.isdir(self.saved_game_dir): - error_dialog = QMessageBox.critical( - self, - "Wrong DCS Saved Games directory.", - self.saved_game_dir + " is not a valid directory", - QMessageBox.StandardButton.Ok, - ) - error_dialog.exec_() - return False - - if self.install_dir_ignore_warning and self.dcs_install_dir == "": - warning_dialog = QMessageBox.warning( - self, - "The DCS Installation directory was not set", - "You set an empty DCS Installation directory! " - "

    Without this directory, DCS Liberation can not replace the MissionScripting.lua for you and will not work properly. " - "In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)." - "

    You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

    " - "

    Are you sure that you want to leave the installation directory empty?" - "

    This is only recommended for expert users!", - QMessageBox.StandardButton.Yes, - QMessageBox.StandardButton.No, - ) - if warning_dialog == QMessageBox.No: - return False - elif not os.path.isdir(self.dcs_install_dir): - error_dialog = QMessageBox.critical( - self, - "Wrong DCS installation directory.", - self.dcs_install_dir - + " is not a valid directory. DCS Liberation requires the installation directory to replace the MissionScripting.lua" - "

    If you ignore this Error, DCS Liberation can not work properly and needs your attention. " - "In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)." - "

    You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.

    " - "

    This is only recommended for expert users!", - QMessageBox.StandardButton.Ignore, - QMessageBox.StandardButton.Ok, - ) - if error_dialog == QMessageBox.Ignore: - self.install_dir_ignore_warning = True - return False - elif not os.path.isdir( - os.path.join(self.dcs_install_dir, "Scripts") - ) and os.path.isfile(os.path.join(self.dcs_install_dir, "bin", "DCS.exe")): - error_dialog = QMessageBox.critical( - self, - "Wrong DCS installation directory.", - self.dcs_install_dir + " is not a valid DCS installation directory", - QMessageBox.StandardButton.Ok, - ) - error_dialog.exec_() - return False - - liberation_install.setup(self.saved_game_dir, self.dcs_install_dir) - liberation_install.save_config() - liberation_theme.save_theme_config() - return True diff --git a/qt_ui/windows/preferences/QLiberationPreferencesWindow.py b/qt_ui/windows/preferences/QLiberationPreferencesWindow.py deleted file mode 100644 index 7363a1907..000000000 --- a/qt_ui/windows/preferences/QLiberationPreferencesWindow.py +++ /dev/null @@ -1,35 +0,0 @@ -from PySide6.QtGui import QIcon, Qt -from PySide6.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout - -from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences - - -class QLiberationPreferencesWindow(QDialog): - def __init__(self): - super(QLiberationPreferencesWindow, self).__init__() - - self.setModal(True) - self.setWindowTitle("Preferences") - self.setMinimumSize(300, 200) - self.setWindowIcon(QIcon("./resources/icon.png")) - self.preferences = QLiberationPreferences() - self.apply_button = QPushButton("Apply") - self.apply_button.clicked.connect(lambda: self.apply()) - self.initUI() - - def initUI(self): - layout = QVBoxLayout() - layout.addWidget(self.preferences) - layout.addStretch() - apply_btn_layout = QHBoxLayout() - apply_btn_layout.addStretch() - apply_btn_layout.addWidget(self.apply_button) - layout.addLayout(apply_btn_layout) - self.setLayout(layout) - - def apply(self): - if self.preferences.apply(): - print("Closing") - self.close() - else: - print("Not Closing") diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py deleted file mode 100644 index 59e008dc6..000000000 --- a/qt_ui/windows/settings/QSettingsWindow.py +++ /dev/null @@ -1,399 +0,0 @@ -import logging -import textwrap -from typing import Callable - -from PySide6.QtCore import QItemSelectionModel, QPoint, QSize, Qt -from PySide6.QtGui import QStandardItem, QStandardItemModel -from PySide6.QtWidgets import ( - QAbstractItemView, - QCheckBox, - QComboBox, - QDialog, - QGridLayout, - QGroupBox, - QLabel, - QListView, - QPushButton, - QSpinBox, - QStackedLayout, - QVBoxLayout, - QWidget, - QScrollArea, -) - -import qt_ui.uiconstants as CONST -from game.game import Game -from game.server import EventStream -from game.settings import ( - BooleanOption, - BoundedFloatOption, - BoundedIntOption, - ChoicesOption, - MinutesOption, - OptionDescription, - Settings, -) -from game.sim import GameUpdateEvents -from qt_ui.widgets.QLabeledWidget import QLabeledWidget -from qt_ui.widgets.spinsliders import FloatSpinSlider, TimeInputs -from qt_ui.windows.GameUpdateSignal import GameUpdateSignal -from qt_ui.windows.settings.plugins import PluginOptionsPage, PluginsPage - - -class CheatSettingsBox(QGroupBox): - def __init__(self, game: Game, apply_settings: Callable[[], None]) -> None: - super().__init__("Cheat Settings") - self.main_layout = QVBoxLayout() - self.setLayout(self.main_layout) - - self.red_ato_checkbox = QCheckBox() - self.red_ato_checkbox.setChecked(game.settings.show_red_ato) - self.red_ato_checkbox.toggled.connect(apply_settings) - - self.frontline_cheat_checkbox = QCheckBox() - self.frontline_cheat_checkbox.setChecked(game.settings.enable_frontline_cheats) - self.frontline_cheat_checkbox.toggled.connect(apply_settings) - - self.base_capture_cheat_checkbox = QCheckBox() - self.base_capture_cheat_checkbox.setChecked( - game.settings.enable_base_capture_cheat - ) - self.base_capture_cheat_checkbox.toggled.connect(apply_settings) - - self.red_ato = QLabeledWidget("Show Red ATO:", self.red_ato_checkbox) - self.main_layout.addLayout(self.red_ato) - self.frontline_cheat = QLabeledWidget( - "Enable Frontline Cheats:", self.frontline_cheat_checkbox - ) - self.main_layout.addLayout(self.frontline_cheat) - self.base_capture_cheat = QLabeledWidget( - "Enable Base Capture Cheat:", self.base_capture_cheat_checkbox - ) - - self.base_runway_state_cheat_checkbox = QCheckBox() - self.base_runway_state_cheat_checkbox.setChecked( - game.settings.enable_runway_state_cheat - ) - self.base_runway_state_cheat_checkbox.toggled.connect(apply_settings) - self.main_layout.addLayout( - QLabeledWidget( - "Enable runway state cheat:", self.base_runway_state_cheat_checkbox - ) - ) - - self.main_layout.addLayout(self.base_capture_cheat) - - @property - def show_red_ato(self) -> bool: - return self.red_ato_checkbox.isChecked() - - @property - def show_frontline_cheat(self) -> bool: - return self.frontline_cheat_checkbox.isChecked() - - @property - def show_base_capture_cheat(self) -> bool: - return self.base_capture_cheat_checkbox.isChecked() - - @property - def enable_runway_state_cheat(self) -> bool: - return self.base_runway_state_cheat_checkbox.isChecked() - - -class AutoSettingsLayout(QGridLayout): - def __init__( - self, - page: str, - section: str, - settings: Settings, - write_full_settings: Callable[[], None], - ) -> None: - super().__init__() - self.settings = settings - self.write_full_settings = write_full_settings - - for row, (name, description) in enumerate(Settings.fields_for(page, section)): - self.add_label(row, description) - if isinstance(description, BooleanOption): - self.add_checkbox_for(row, name, description) - elif isinstance(description, ChoicesOption): - self.add_combobox_for(row, name, description) - elif isinstance(description, BoundedFloatOption): - self.add_float_spin_slider_for(row, name, description) - elif isinstance(description, BoundedIntOption): - self.add_spinner_for(row, name, description) - elif isinstance(description, MinutesOption): - self.add_duration_controls_for(row, name, description) - else: - raise TypeError(f"Unhandled option type: {description}") - - def add_label(self, row: int, description: OptionDescription) -> None: - wrapped_title = "
    ".join(textwrap.wrap(description.text, width=55)) - text = f"{wrapped_title}" - if description.detail is not None: - wrapped = "
    ".join(textwrap.wrap(description.detail, width=55)) - text += f"
    {wrapped}" - label = QLabel(text) - if description.tooltip is not None: - label.setToolTip(description.tooltip) - self.addWidget(label, row, 0) - - def add_checkbox_for(self, row: int, name: str, description: BooleanOption) -> None: - def on_toggle(value: bool) -> None: - if description.invert: - value = not value - self.settings.__dict__[name] = value - if description.causes_expensive_game_update: - self.write_full_settings() - - checkbox = QCheckBox() - value = self.settings.__dict__[name] - if description.invert: - value = not value - checkbox.setChecked(value) - checkbox.toggled.connect(on_toggle) - self.addWidget(checkbox, row, 1, Qt.AlignRight) - - def add_combobox_for(self, row: int, name: str, description: ChoicesOption) -> None: - combobox = QComboBox() - - def on_changed(index: int) -> None: - self.settings.__dict__[name] = combobox.itemData(index) - - for text, value in description.choices.items(): - combobox.addItem(text, value) - combobox.setCurrentText( - description.text_for_value(self.settings.__dict__[name]) - ) - combobox.currentIndexChanged.connect(on_changed) - self.addWidget(combobox, row, 1, Qt.AlignRight) - - def add_float_spin_slider_for( - self, row: int, name: str, description: BoundedFloatOption - ) -> None: - spinner = FloatSpinSlider( - description.min, - description.max, - self.settings.__dict__[name], - divisor=description.divisor, - ) - - def on_changed() -> None: - self.settings.__dict__[name] = spinner.value - - spinner.spinner.valueChanged.connect(on_changed) - self.addLayout(spinner, row, 1, Qt.AlignRight) - - def add_spinner_for( - self, row: int, name: str, description: BoundedIntOption - ) -> None: - def on_changed(value: int) -> None: - self.settings.__dict__[name] = value - if description.causes_expensive_game_update: - self.write_full_settings() - - spinner = QSpinBox() - spinner.setMinimum(description.min) - spinner.setMaximum(description.max) - spinner.setValue(self.settings.__dict__[name]) - - spinner.valueChanged.connect(on_changed) - self.addWidget(spinner, row, 1, Qt.AlignRight) - - def add_duration_controls_for( - self, row: int, name: str, description: MinutesOption - ) -> None: - inputs = TimeInputs( - self.settings.__dict__[name], description.min, description.max - ) - - def on_changed() -> None: - self.settings.__dict__[name] = inputs.value - - inputs.spinner.valueChanged.connect(on_changed) - self.addLayout(inputs, row, 1, Qt.AlignRight) - - -class AutoSettingsGroup(QGroupBox): - def __init__( - self, - page: str, - section: str, - settings: Settings, - write_full_settings: Callable[[], None], - ) -> None: - super().__init__(section) - self.setLayout(AutoSettingsLayout(page, section, settings, write_full_settings)) - - -class AutoSettingsPageLayout(QVBoxLayout): - def __init__( - self, - page: str, - settings: Settings, - write_full_settings: Callable[[], None], - ) -> None: - super().__init__() - self.setAlignment(Qt.AlignTop) - - for section in Settings.sections(page): - self.addWidget( - AutoSettingsGroup(page, section, settings, write_full_settings) - ) - - -class AutoSettingsPage(QWidget): - def __init__( - self, - page: str, - settings: Settings, - write_full_settings: Callable[[], None], - ) -> None: - super().__init__() - layout = QVBoxLayout() - self.setLayout(layout) - - scroll_content = QWidget() - scroll_content.setLayout( - AutoSettingsPageLayout(page, settings, write_full_settings) - ) - scroll = QScrollArea() - scroll.setWidgetResizable(True) - scroll.setWidget(scroll_content) - scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - layout.addWidget(scroll) - - -class QSettingsWindow(QDialog): - def __init__(self, game: Game): - super().__init__() - - self.game = game - self.pluginsPage = None - self.pluginsOptionsPage = None - - self.pages: dict[str, AutoSettingsPage] = {} - for page in Settings.pages(): - self.pages[page] = AutoSettingsPage(page, game.settings, self.applySettings) - - self.setModal(True) - self.setWindowTitle("Settings") - self.setWindowIcon(CONST.ICONS["Settings"]) - self.setMinimumSize(600, 250) - - self.initUi() - - def initUi(self): - self.layout = QGridLayout() - - self.categoryList = QListView() - self.right_layout = QStackedLayout() - - self.categoryList.setMaximumWidth(175) - - self.categoryModel = QStandardItemModel(self.categoryList) - - self.categoryList.setIconSize(QSize(32, 32)) - - for name, page in self.pages.items(): - page_item = QStandardItem(name) - if name in CONST.ICONS: - page_item.setIcon(CONST.ICONS[name]) - else: - page_item.setIcon(CONST.ICONS["Generator"]) - page_item.setEditable(False) - page_item.setSelectable(True) - self.categoryModel.appendRow(page_item) - self.right_layout.addWidget(page) - - self.initCheatLayout() - cheat = QStandardItem("Cheat Menu") - cheat.setIcon(CONST.ICONS["Cheat"]) - cheat.setEditable(False) - cheat.setSelectable(True) - self.categoryModel.appendRow(cheat) - self.right_layout.addWidget(self.cheatPage) - - self.pluginsPage = PluginsPage(self.game.lua_plugin_manager) - plugins = QStandardItem("LUA Plugins") - plugins.setIcon(CONST.ICONS["Plugins"]) - plugins.setEditable(False) - plugins.setSelectable(True) - self.categoryModel.appendRow(plugins) - self.right_layout.addWidget(self.pluginsPage) - - self.pluginsOptionsPage = PluginOptionsPage(self.game.lua_plugin_manager) - pluginsOptions = QStandardItem("LUA Plugins Options") - pluginsOptions.setIcon(CONST.ICONS["PluginsOptions"]) - pluginsOptions.setEditable(False) - pluginsOptions.setSelectable(True) - self.categoryModel.appendRow(pluginsOptions) - self.right_layout.addWidget(self.pluginsOptionsPage) - - self.categoryList.setSelectionBehavior(QAbstractItemView.SelectRows) - self.categoryList.setModel(self.categoryModel) - self.categoryList.selectionModel().setCurrentIndex( - self.categoryList.indexAt(QPoint(1, 1)), QItemSelectionModel.Select - ) - self.categoryList.selectionModel().selectionChanged.connect( - self.onSelectionChanged - ) - - self.layout.addWidget(self.categoryList, 0, 0, 1, 1) - self.layout.addLayout(self.right_layout, 0, 1, 5, 1) - - self.setLayout(self.layout) - - def initCheatLayout(self): - self.cheatPage = QWidget() - self.cheatLayout = QVBoxLayout() - self.cheatPage.setLayout(self.cheatLayout) - - self.cheat_options = CheatSettingsBox(self.game, self.applySettings) - self.cheatLayout.addWidget(self.cheat_options) - - self.moneyCheatBox = QGroupBox("Money Cheat") - self.moneyCheatBox.setAlignment(Qt.AlignTop) - self.moneyCheatBoxLayout = QGridLayout() - self.moneyCheatBox.setLayout(self.moneyCheatBoxLayout) - - cheats_amounts = [25, 50, 100, 200, 500, 1000, -25, -50, -100, -200] - for i, amount in enumerate(cheats_amounts): - if amount > 0: - btn = QPushButton("Cheat +" + str(amount) + "M") - btn.setProperty("style", "btn-success") - else: - btn = QPushButton("Cheat " + str(amount) + "M") - btn.setProperty("style", "btn-danger") - btn.clicked.connect(self.cheatLambda(amount)) - self.moneyCheatBoxLayout.addWidget(btn, i / 2, i % 2) - self.cheatLayout.addWidget(self.moneyCheatBox, stretch=1) - - def cheatLambda(self, amount): - return lambda: self.cheatMoney(amount) - - def cheatMoney(self, amount): - logging.info("CHEATING FOR AMOUNT : " + str(amount) + "M") - self.game.blue.budget += amount - GameUpdateSignal.get_instance().updateGame(self.game) - - def applySettings(self): - self.game.settings.show_red_ato = self.cheat_options.show_red_ato - self.game.settings.enable_frontline_cheats = ( - self.cheat_options.show_frontline_cheat - ) - self.game.settings.enable_base_capture_cheat = ( - self.cheat_options.show_base_capture_cheat - ) - self.game.settings.enable_runway_state_cheat = ( - self.cheat_options.enable_runway_state_cheat - ) - - events = GameUpdateEvents() - self.game.compute_unculled_zones(events) - EventStream.put_nowait(events) - GameUpdateSignal.get_instance().updateGame(self.game) - - def onSelectionChanged(self): - index = self.categoryList.selectionModel().currentIndex().row() - self.right_layout.setCurrentIndex(index) diff --git a/qt_ui/windows/settings/plugins.py b/qt_ui/windows/settings/plugins.py deleted file mode 100644 index eef914995..000000000 --- a/qt_ui/windows/settings/plugins.py +++ /dev/null @@ -1,72 +0,0 @@ -from PySide6.QtCore import Qt -from PySide6.QtWidgets import ( - QCheckBox, - QGridLayout, - QGroupBox, - QLabel, - QVBoxLayout, - QWidget, -) - -from game.plugins import LuaPlugin, LuaPluginManager - - -class PluginsBox(QGroupBox): - def __init__(self, manager: LuaPluginManager) -> None: - super().__init__("Plugins") - - layout = QGridLayout() - layout.setAlignment(Qt.AlignTop) - self.setLayout(layout) - - for row, plugin in enumerate(manager.iter_plugins()): - if not plugin.show_in_ui: - continue - - layout.addWidget(QLabel(plugin.name), row, 0) - - checkbox = QCheckBox() - checkbox.setChecked(plugin.enabled) - checkbox.toggled.connect(plugin.set_enabled) - layout.addWidget(checkbox, row, 1) - - -class PluginsPage(QWidget): - def __init__(self, manager: LuaPluginManager) -> None: - super().__init__() - - layout = QVBoxLayout() - layout.setAlignment(Qt.AlignTop) - self.setLayout(layout) - - layout.addWidget(PluginsBox(manager)) - - -class PluginOptionsBox(QGroupBox): - def __init__(self, plugin: LuaPlugin) -> None: - super().__init__(plugin.name) - - layout = QGridLayout() - layout.setAlignment(Qt.AlignTop) - self.setLayout(layout) - - for row, option in enumerate(plugin.options): - layout.addWidget(QLabel(option.name), row, 0) - - checkbox = QCheckBox() - checkbox.setChecked(option.enabled) - checkbox.toggled.connect(option.set_enabled) - layout.addWidget(checkbox, row, 1) - - -class PluginOptionsPage(QWidget): - def __init__(self, manager: LuaPluginManager) -> None: - super().__init__() - - layout = QVBoxLayout() - layout.setAlignment(Qt.AlignTop) - self.setLayout(layout) - - for plugin in manager.iter_plugins(): - if plugin.options: - layout.addWidget(PluginOptionsBox(plugin)) diff --git a/qt_ui/windows/stats/QAircraftChart.py b/qt_ui/windows/stats/QAircraftChart.py deleted file mode 100644 index 0ec67d71c..000000000 --- a/qt_ui/windows/stats/QAircraftChart.py +++ /dev/null @@ -1,59 +0,0 @@ -from PySide6 import QtCharts -from PySide6.QtCore import QPoint, Qt -from PySide6.QtGui import QPainter -from PySide6.QtWidgets import QFrame, QGridLayout - -from game import Game - - -class QAircraftChart(QFrame): - def __init__(self, game: Game): - super(QAircraftChart, self).__init__() - self.game = game - self.initUi() - - def initUi(self): - self.layout = QGridLayout() - self.generateUnitCharts() - self.setLayout(self.layout) - - def generateUnitCharts(self): - self.alliedAircraft = [ - d.allied_units.aircraft_count for d in self.game.game_stats.data_per_turn - ] - self.enemyAircraft = [ - d.enemy_units.aircraft_count for d in self.game.game_stats.data_per_turn - ] - - self.alliedAircraftSerie = QtCharts.QLineSeries() - self.alliedAircraftSerie.setName("Allied aircraft count") - for a, i in enumerate(self.alliedAircraft): - self.alliedAircraftSerie.append(QPoint(a, i)) - - self.enemyAircraftSerie = QtCharts.QLineSeries() - self.enemyAircraftSerie.setColor(Qt.red) - self.enemyAircraftSerie.setName("Enemy aircraft count") - for a, i in enumerate(self.enemyAircraft): - self.enemyAircraftSerie.append(QPoint(a, i)) - - self.chart = QtCharts.QChart() - self.chart.addSeries(self.alliedAircraftSerie) - self.chart.addSeries(self.enemyAircraftSerie) - self.chart.setTitle("Aircraft forces over time") - - self.chart.createDefaultAxes() - self.chart.axisX().setTitleText("Turn") - self.chart.axisX().setLabelFormat("%i") - self.chart.axisX().setRange(0, len(self.alliedAircraft)) - self.chart.axisX().applyNiceNumbers() - - self.chart.axisY().setLabelFormat("%i") - self.chart.axisY().setRange( - 0, max(max(self.alliedAircraft), max(self.enemyAircraft)) + 10 - ) - self.chart.axisY().applyNiceNumbers() - - self.chartView = QtCharts.QChartView(self.chart) - self.chartView.setRenderHint(QPainter.Antialiasing) - - self.layout.addWidget(self.chartView, 0, 0) diff --git a/qt_ui/windows/stats/QArmorChart.py b/qt_ui/windows/stats/QArmorChart.py deleted file mode 100644 index 5f8b280c6..000000000 --- a/qt_ui/windows/stats/QArmorChart.py +++ /dev/null @@ -1,59 +0,0 @@ -from PySide6 import QtCharts -from PySide6.QtCore import QPoint, Qt -from PySide6.QtGui import QPainter -from PySide6.QtWidgets import QFrame, QGridLayout - -from game import Game - - -class QArmorChart(QFrame): - def __init__(self, game: Game): - super(QArmorChart, self).__init__() - self.game = game - self.initUi() - - def initUi(self): - self.layout = QGridLayout() - self.generateUnitCharts() - self.setLayout(self.layout) - - def generateUnitCharts(self): - self.alliedArmor = [ - d.allied_units.vehicles_count for d in self.game.game_stats.data_per_turn - ] - self.enemyArmor = [ - d.enemy_units.vehicles_count for d in self.game.game_stats.data_per_turn - ] - - self.alliedArmorSerie = QtCharts.QLineSeries() - self.alliedArmorSerie.setName("Allied vehicle count") - for a, i in enumerate(self.alliedArmor): - self.alliedArmorSerie.append(QPoint(a, i)) - - self.enemyArmorSerie = QtCharts.QLineSeries() - self.enemyArmorSerie.setColor(Qt.red) - self.enemyArmorSerie.setName("Enemy vehicle count") - for a, i in enumerate(self.enemyArmor): - self.enemyArmorSerie.append(QPoint(a, i)) - - self.chart = QtCharts.QChart() - self.chart.addSeries(self.alliedArmorSerie) - self.chart.addSeries(self.enemyArmorSerie) - self.chart.setTitle("Combat vehicles over time") - - self.chart.createDefaultAxes() - self.chart.axisX().setTitleText("Turn") - self.chart.axisX().setLabelFormat("%i") - self.chart.axisX().setRange(0, len(self.alliedArmor)) - self.chart.axisX().applyNiceNumbers() - - self.chart.axisY().setLabelFormat("%i") - self.chart.axisY().setRange( - 0, max(max(self.alliedArmor), max(self.enemyArmor)) + 10 - ) - self.chart.axisY().applyNiceNumbers() - - self.chartView = QtCharts.QChartView(self.chart) - self.chartView.setRenderHint(QPainter.Antialiasing) - - self.layout.addWidget(self.chartView, 0, 0) diff --git a/qt_ui/windows/stats/QStatsWindow.py b/qt_ui/windows/stats/QStatsWindow.py deleted file mode 100644 index b3a2edbbd..000000000 --- a/qt_ui/windows/stats/QStatsWindow.py +++ /dev/null @@ -1,26 +0,0 @@ -from PySide6.QtWidgets import QDialog, QGridLayout, QTabWidget - -import qt_ui.uiconstants as CONST -from game.game import Game -from qt_ui.windows.stats.QAircraftChart import QAircraftChart -from qt_ui.windows.stats.QArmorChart import QArmorChart - - -class QStatsWindow(QDialog): - def __init__(self, game: Game): - super(QStatsWindow, self).__init__() - - self.game = game - self.setModal(True) - self.setWindowTitle("Stats") - self.setWindowIcon(CONST.ICONS["Statistics"]) - self.setMinimumSize(600, 300) - - self.layout = QGridLayout() - self.aircraft_charts = QAircraftChart(self.game) - self.armor_charts = QArmorChart(self.game) - self.tabview = QTabWidget() - self.tabview.addTab(self.aircraft_charts, "Aircraft") - self.tabview.addTab(self.armor_charts, "Armor") - self.layout.addWidget(self.tabview, 0, 0) - self.setLayout(self.layout) diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 31eab74cd..000000000 --- a/requirements.txt +++ /dev/null @@ -1,69 +0,0 @@ -altgraph==0.17.4 -annotated-types==0.6.0 -anyio==3.7.1 -asgiref==3.7.2 -attrs==23.1.0 -black==23.11.0 -certifi==2023.11.17 -cfgv==3.4.0 -click==8.1.7 -colorama==0.4.6 -coverage==7.3.2 -distlib==0.3.7 -exceptiongroup==1.2.0 -Faker==20.1.0 -fastapi==0.109.1 -filelock==3.13.1 -future==0.18.3 -h11==0.14.0 -httptools==0.6.1 -identify==2.5.32 -idna==3.6 -iniconfig==2.0.0 -Jinja2==3.1.3 -MarkupSafe==2.1.3 -mypy==1.7.1 -mypy-extensions==1.0.0 -nodeenv==1.8.0 -numpy==1.26.2 -packaging==23.2 -pathspec==0.11.2 -pefile==2023.2.7 -Pillow==10.2.0 -platformdirs==4.0.0 -pluggy==1.3.0 -pre-commit==3.5.0 -pydantic==2.5.2 -pydantic-settings==2.1.0 -pydantic_core==2.14.5 -pydcs @ git+https://github.com/zhexu14/dcs@ea33d9e2cb15390d2542f20f7e2194041baed9fe -pyinstaller==5.13.1 -pyinstaller-hooks-contrib==2023.6 -pyproj==3.6.1 -PySide6==6.4.1 -PySide6-Addons==6.4.1 -PySide6-Essentials==6.4.1 -pytest==7.4.3 -pytest-cov==4.1.0 -pytest-mock==3.12.0 -python-dateutil==2.8.2 -python-dotenv==1.0.0 -pywin32-ctypes==0.2.2 -PyYAML==6.0.1 -shapely==2.0.2 -shiboken6==6.4.1 -six==1.16.0 -sniffio==1.3.0 -starlette==0.35.1 -tabulate==0.9.0 -tomli==2.0.1 -types-Jinja2==2.11.9 -types-MarkupSafe==1.1.10 -types-Pillow==9.3.0.4 -types-PyYAML==6.0.12.12 -types-tabulate==0.9.0.3 -typing_extensions==4.8.0 -uvicorn==0.24.0.post1 -virtualenv==20.24.7 -watchfiles==0.21.0 -websockets==12.0 diff --git a/resources/briefing/templates/briefingtemplate_CN.j2 b/resources/briefing/templates/briefingtemplate_CN.j2 deleted file mode 100644 index a5a0dc01c..000000000 --- a/resources/briefing/templates/briefingtemplate_CN.j2 +++ /dev/null @@ -1,114 +0,0 @@ -DCS Liberation 第 {{ game.turn }} 回合 -==================== - -简报中的大部分信息,包括通讯、飞行计划等,都可以在你的膝板中找到。 - -当前局势: -==================== -{% if not frontlines %} -目前没有地面战斗发生。 -{% endif %} -{% if frontlines %} -{%+ for frontline in frontlines %} -{% if frontline.player_zero %} -前线已经没有任何地面力量来进行防御了。 情况极其危急,我们将不可避免地失去{{ frontline.player_base.name }} 和 {{ frontline.enemy_base.name }}之间的区域控制权。 -{% endif %} -{% if frontline.enemy_zero %} -我们已经击溃了敌军部队,将在 {{ frontline.enemy_base.name }} 区域取得重大突破。 -{% endif %} -{% if not frontline.player_zero %} -{# Pick a random sentence to describe each frontline #} -{% set fl_sent1 %}在 {{ frontline.player_base.name }} 和 {{frontline.enemy_base.name}} 之间仍有交火发生。 {%+ endset %} -{% set fl_sent2 %}在 {{frontline.player_base.name}} 和 {{frontline.enemy_base.name}} 之间的地面战斗仍在继续。 {%+ endset %} -{% set fl_sent3 %}我们 {{frontline.player_base.name}} 的部队,正在对抗来自 {{frontline.enemy_base.name}}的敌军部队。 {%+ endset %} -{% set fl_sent4 %}来自 {{frontline.player_base.name}} 的我军部队,正与来自 {{frontline.enemy_base.name}} 的敌军部队交战。 {%+ endset %} -{% set fl_sent5 %}当前的战斗前线在 {{frontline.player_base.name}} 和 {{frontline.enemy_base.name}} 之间。 {%+ endset %} -{% set frontline_sentences = [fl_sent1, fl_sent2, fl_sent3, fl_sent4, fl_sent5] %} -{{ frontline_sentences | random }} -{%- if frontline.advantage %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -我军部队将从这个位置出发向敌军发起进攻,鉴于敌军已经寡不敌众,毫无疑问我军将取得进展。 - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -我军地面部队将从这个位置出发,集中力量优先摧毁敌方有生力量,然后再向 {{frontline.enemy_base.name}} 进发。 敌军已经寡不敌众,此举或将给予他们致命一击。" - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -我军部队将从这个位置出发,集中力量突击 {{ frontline.enemy_base.name }} 。 - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -我们的地面部队将在当前位置驻守防御。我们并不期望敌人会来一次突击。 - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{%- else %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -我们的地面部队将试图利用优势数量从当前位置向敌军发起一次大胆的突击。这次行动有些冒险,敌人也可能会发动反击。 - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -我们的地面部队将试图利用优势数量从当前位置向敌军发起一次大胆的突击。这次行动有些冒险,敌人也可能会发动反击。 - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -我们的地面部队将从当前位置向 {{frontline.enemy_base.name}} 发起一次主要突破攻势。祝他们好运,预计会有敌方反击。 - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -我们的地面部队奉命驻守在当前位置,以防御敌人的攻击。 预计敌方即将发起突击行动。 - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{% endif %} -{% endif %} - -{%+ endfor %}{% endif %} - -本小队: -==================== -{% for flight in flights if flight.client_units %} --------------------------------------------------- -{{ flight.flight_type }} {{ flight.units[0].type }} x {{flight.size}}, departing in {{ flight.departure_delay }}, {{ flight.package.target.name}} -频率 : {{ flight|intra_flight_channel }} -{% for waypoint in flight.waypoints %} -{{ loop.index0 }} {{waypoint|waypoint_timing("Depart ")}}-- {{waypoint.name}} : {{ waypoint.description}} -{% endfor %} ---------------------------------------------------{% endfor %} - - -{%- if allied_flights_by_departure|length > 0 %} -其他友军单位飞行计划: -==================== -{% for dep in allied_flights_by_departure %} -{{ dep }} ---------------------------------------------------- -{% for flight in allied_flights_by_departure[dep] %} -{{ flight.flight_type }} {{ flight.units[0].type }} x {{flight.size}}, departing in {{ flight.departure_delay }}, {{ flight.package.target.name}} -{% endfor %} -{% endfor %} -{% endif %} - -{%- if dynamic_runways|length > 0 %} -航母及FARPs: -==================== -{% for runway in dynamic_runways %} -{{ runway.airfield_name}} --------------------------------------------------- -无线电 : {{ runway.atc }} -TACAN : {{ runway.tacan }} {{ runway.tacan_callsign }} -{% if runway.icls %}ILS/ICLS频道: {{ runway.icls }} -{% endif %} - -{% endfor %} -{% endif %} -{%- if awacs|length > 0 %} -AWACS: -==================== -{% for i in awacs %}{{ i.callsign }} -- 频率 : {{i.freq.mhz}} -{% endfor %} -{% endif %} - -{%- if jtacs|length > 0 %} -JTACS [F-10 菜单] : -==================== -{% for jtac in jtacs %}前线 {{ jtac.region }} -- 激光编码 : {{ jtac.code }}, 频率 : {{ jtac.freq.mhz }} -{% endfor %} -{% endif %} diff --git a/resources/briefing/templates/briefingtemplate_EN.j2 b/resources/briefing/templates/briefingtemplate_EN.j2 deleted file mode 100644 index 67fc74ebc..000000000 --- a/resources/briefing/templates/briefingtemplate_EN.j2 +++ /dev/null @@ -1,114 +0,0 @@ -DCS Liberation Turn {{ game.turn }} -==================== - -Most briefing information, including communications and flight plan information, can be found on your kneeboard. - -Current situation: -==================== -{% if not frontlines %} -There are currently no fights on the ground. -{% endif %} -{% if frontlines %} -{%+ for frontline in frontlines %} -{% if frontline.player_zero %} -We do not have a single vehicle available to hold our position. The situation is critical, and we will lose ground inevitably between {{ frontline.player_base.name }} and {{ frontline.enemy_base.name }}. -{% endif %} -{% if frontline.enemy_zero %} -The enemy forces have been crushed, we will be able to make significant progress toward {{ frontline.enemy_base.name }} -{% endif %} -{% if not frontline.player_zero %} -{# Pick a random sentence to describe each frontline #} -{% set fl_sent1 %}There are combats between {{ frontline.player_base.name }} and {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent2 %}The war on the ground is still going on between {{frontline.player_base.name}} and {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent3 %}Our ground forces in {{frontline.player_base.name}} are opposed to enemy forces based in {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent4 %}Our forces from {{frontline.player_base.name}} are fighting enemies based in {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent5 %}There is an active frontline between {{frontline.player_base.name}} and {{frontline.enemy_base.name}}. {%+ endset %} -{% set frontline_sentences = [fl_sent1, fl_sent2, fl_sent3, fl_sent4, fl_sent5] %} -{{ frontline_sentences | random }} -{%- if frontline.advantage %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -On this location, our ground forces will try to make progress against the enemy. As the enemy is outnumbered, our forces should have no issue making progress. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -On this location, our ground forces will focus on the destruction of enemy assets, before attempting to make progress toward {{frontline.enemy_base.name}}. The enemy is already outnumbered, and this maneuver might draw a final blow to their forces." - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -On this location, our ground forces will focus on progression toward {{ frontline.enemy_base.name }} - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -On this location, our ground forces will hold position. We are not expecting an enemy assault. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{%- else %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -On this location, our ground forces will try an audacious assault against enemies in superior numbers. The operation is risky, and the enemy might counter attack. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -On this location, our ground forces will try an audacious assault against enemies in superior numbers. The operation is risky, and the enemy might counter attack. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -On this location, our ground forces have been ordered to rush toward {{frontline.enemy_base.name}}. Wish them luck... We are also expecting a counter attack. - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -On this location, our ground forces have been ordered to hold still, and defend against enemy attacks. An enemy assault might be iminent. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{% endif %} -{% endif %} - -{%+ endfor %}{% endif %} - -Your flights: -==================== -{% for flight in flights if flight.client_units %} --------------------------------------------------- -{{ flight.flight_type }} {{ flight.units[0].type }} x {{ flight.size }}, departing in {{ flight.departure_delay }}, {{ flight.package.target.name}} -Freq : {{ flight|intra_flight_channel }} -{% for waypoint in flight.waypoints %} -{{ loop.index0 }} {{waypoint|waypoint_timing("Depart ")}}-- {{waypoint.name}} : {{ waypoint.description}} -{% endfor %} ---------------------------------------------------{% endfor %} - - -{%- if allied_flights_by_departure|length > 0 %} -Planned ally flights: -==================== -{% for dep in allied_flights_by_departure %} -{{ dep }} ---------------------------------------------------- -{% for flight in allied_flights_by_departure[dep] %} -{{ flight.flight_type }} {{ flight.units[0].type }} x {{flight.size}}, departing in {{ flight.departure_delay }}, {{ flight.package.target.name}} -{% endfor %} -{% endfor %} -{% endif %} - -{%- if dynamic_runways|length > 0 %} -Carriers and FARPs: -==================== -{% for runway in dynamic_runways %} -{{ runway.airfield_name}} --------------------------------------------------- -RADIO : {{ runway.atc }} -TACAN : {{ runway.tacan }} {{ runway.tacan_callsign }} -{% if runway.icls %}ICLS Channel: {{ runway.icls }} -{% endif %} - -{% endfor %} -{% endif %} -{%- if awacs|length > 0 %} -AWACS: -==================== -{% for i in awacs %}{{ i.callsign }} -- Freq : {{i.freq.mhz}} -{% endfor %} -{% endif %} - -{%- if jtacs|length > 0 %} -JTACS [F-10 Menu] : -==================== -{% for jtac in jtacs %}Frontline {{ jtac.region }} -- Code : {{ jtac.code }}, Freq : {{ jtac.freq.mhz }} -{% endfor %} -{% endif %} \ No newline at end of file diff --git a/resources/briefing/templates/briefingtemplate_FR.j2 b/resources/briefing/templates/briefingtemplate_FR.j2 deleted file mode 100644 index 2672cb44c..000000000 --- a/resources/briefing/templates/briefingtemplate_FR.j2 +++ /dev/null @@ -1,114 +0,0 @@ -DCS Liberation Tour {{ game.turn }} -==================== - -La plupart des informations importantes, en particulier votre plan de vol et les fréquences de communications à utiliser, sont disponibles sur votre kneeboard. - -Situation actuelle : -==================== -{% if not frontlines %} -Pour le moment, il n'y a pas de combats au sol. -{% endif %} -{% if frontlines %} -{%+ for frontline in frontlines %} -{% if frontline.player_zero %} -Nous n'avons pas un seul véhicule disponible pour tenir nos positions. La situation est critique, nous allons inévitablement perdre du terrain sur le front entre {{ frontline.player_base.name }} et {{ frontline.enemy_base.name }}. -{% endif %} -{% if frontline.enemy_zero %} -Les forces ennemies ont été écrasées, nous devrions être capable de progresser rapidement vers {{ frontline.enemy_base.name }} -{% endif %} -{% if not frontline.player_zero %} -{# Pick a random sentence to describe each frontline #} -{% set fl_sent1 %}Il y a des comabats entre {{ frontline.player_base.name }} et {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent2 %}Au sol, les combats se poursuivent entre {{frontline.player_base.name}} et {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent3 %}Nos forces au sol, basées à {{frontline.player_base.name}} sont opposées aux forces ennemies provenant de {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent4 %}Nos forces de {{frontline.player_base.name}} se battent contre les ennemis basés à {{frontline.enemy_base.name}}. {%+ endset %} -{% set fl_sent5 %}Il y a une ligne de front active entre {{frontline.player_base.name}} et {{frontline.enemy_base.name}}. {%+ endset %} -{% set frontline_sentences = [fl_sent1, fl_sent2, fl_sent3, fl_sent4, fl_sent5] %} -{{ frontline_sentences | random }} -{%- if frontline.advantage %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -Sur ce front, nos forces vont tenter de progresser. Comme l'ennemi est en infériorité numérique, nous sommes confiant sur l'issue du combat. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -Sur ce front, nos forces vont se focaliser sur la destruction des ennemis avant de tenter une progression vers {{frontline.enemy_base.name}}. L'ennemi est déjà en infériorité, cette manoeuvre pourrait porter le coup final." - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -Sur ce front, nos forces vont tenter une progression rapide vers {{ frontline.enemy_base.name }} - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -Sur ce front, nos forces vont garder leurs positions. Nous ne nous attendons pas à un assaut de l'ennemi. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{%- else %} - {%- if frontline.stance == frontline.combat_stances.AGGRESSIVE %} -Sur ce front, nos forces au sol vont tenter un assaut audacieux contre un ennemi en surnombre. L'opération est périlleuse, et l'ennemi risque de contre-attaquer. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.ELIMINATION %} -Sur ce front, nos forces au sol vont tenter une manoeuvre audacieuse pour éliminer des ennemis en surnombre. L'opération est périlleuse, et l'ennemi risque de contre-attaquer. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.BREAKTHROUGH %} -Sur ce front, nos forces vont se précipiter sur l'objectif {{frontline.enemy_base.name}}, malgré leur infériorité numérique. Souhaitons-leur bonne chance... Nous nous attendons aussi à une contre-attaque. - {% endif %} - {%- if frontline.stance in [frontline.combat_stances.DEFENSIVE, frontline.combat_stances.AMBUSH] %} -Sur ce front, nos forces au sol renforcent leurs positions, et se préparent à défendre. Un assaut ennemi serait imminent. - {% endif %} - {%- if frontline.stance == frontline.combat_stances.RETREAT %} -{# TODO: Write a retreat sentence #} - {% endif %} -{% endif %} -{% endif %} - -{%+ endfor %}{% endif %} - -Vols : -========== -{% for flight in flights if flight.client_units %} --------------------------------------------------- -{{ flight.flight_type }} {{ flight.units[0].type }} x {{flight.size}}, départ dans {{ flight.departure_delay }}, {{ flight.package.target.name}} -Fréq : {{ flight|intra_flight_channel }} -{% for waypoint in flight.waypoints %} -{{ loop.index0 }} {{waypoint|waypoint_timing("Départ dans ")}}-- {{waypoint.name}} : {{ waypoint.description}} -{% endfor %} ---------------------------------------------------{% endfor %} - - -{%- if allied_flights_by_departure|length > 0 %} -Vols alliés prévus : -==================== -{% for dep in allied_flights_by_departure %} -{{ dep }} ---------------------------------------------------- -{% for flight in allied_flights_by_departure[dep] %} -{{ flight.flight_type }} {{ flight.units[0].type }} x {{flight.size}}, départ dans {{ flight.departure_delay }}, {{ flight.package.target.name}} -{% endfor %} -{% endfor %} -{% endif %} - -{%- if dynamic_runways|length > 0 %} -Porte-avions et FARPS : -======================= -{% for runway in dynamic_runways %} -{{ runway.airfield_name}} --------------------------------------------------- -RADIO : {{ runway.atc }} -TACAN : {{ runway.tacan }} {{ runway.tacan_callsign }} -{% if runway.icls %}Channel ICLS : {{ runway.icls }} -{% endif %} -{% endif %} - -{% endfor %} -{%- if awacs|length > 0 %} -AWACS: -==================== -{% for i in awacs %}{{ i.callsign }} -- Fréq : {{i.freq.mhz}} -{% endfor %} -{% endif %} - -{%- if jtacs|length > 0 %} -JTACS [Menu F-10] : -==================== -{% for jtac in jtacs %}Ligne de front {{ jtac.region }} -- Code : {{ jtac.code }}, Fréq : {{ jtac.freq.mhz }} -{% endfor %} -{% endif %} \ No newline at end of file diff --git a/resources/campaigns/TblisiGap.miz b/resources/campaigns/TblisiGap.miz deleted file mode 100644 index c8bcb5bcb..000000000 Binary files a/resources/campaigns/TblisiGap.miz and /dev/null differ diff --git a/resources/campaigns/TblisiGap.yaml b/resources/campaigns/TblisiGap.yaml deleted file mode 100644 index 91dd28b9f..000000000 --- a/resources/campaigns/TblisiGap.yaml +++ /dev/null @@ -1,86 +0,0 @@ ---- -name: Caucasus - The Tblisi Gap -theater: Caucasus -authors: Sith1144 -description:

    A 1980 Cold-war-gone-hot campaign set in the hilly terrain between Tblisi and Kutaisi. Made for the Hind and Hip with a narrow front with lots of targets. Can also be played as Blufor Cold War vs GDR 1985 or as Blufor Modern vs a modern opfor faction. Recommended way to play is focusing on helicopters, with aggressive culling (50-60km is workable, maybe even lower)

    -recommended_player_faction: Russia 1975 (Mi-24P) -recommended_enemy_faction: Germany 1990 -recommended_start_date: 1980-09-21 6:40:00 -miz: TblisiGap.miz -performance: 2 -version: "10.4" -squadrons: - #Vaziani, blufor jet base - 31: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - - F-14A Tomcat (Block 135-GR Late) - - F/A-18C Hornet (Lot 20) - - primary: TARCAP - secondary: any - aircraft: - - MiG-21bis Fishbed-N - - F-16CM Fighting Falcon (Block 50) - - F-5E Tiger II - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-17M4 Fitter-K - - AJS-37 Viggen - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - A-10C Thunderbolt II (Suite 3) - - A-4E Skyhawk - - A-10A Thunderbolt II - - primary: Refueling - - primary: AEW&C - #Tbilisi-Lochini, blue helicopter base - 29: - - primary: CAS - aircraft: - - Mi-24P Hind-F - - AV-8B Harrier II Night Attack - - Ka-50 Hokum - - AH-64D Apache Longbow - - primary: CAS - aircraft: - - Ka-50 Hokum - - SA 342M Gazelle - - Mi-24V Hind-E - - primary: Transport - aircraft: - - Mi-8MTV2 Hip - - UH-1H Iroquois - #frontline FARP, called "FARP Mayhem" - FARP Mayhem: - - primary: CAS - aircraft: - - AH-1W SuperCobra - - AH-64D Apache Longbow - - SA 342M Gazelle - - Ka-50 Hokum - - Mi-24V Hind-E - #Kutaisi, primary opfor base - 25: - - primary: BAI - aircraft: - - Tornado IDS - - Su-17M4 Fitter-K - - Su-24M Fencer-D - - primary: BARCAP - aircraft: - - F-16CM Fighting Falcon (Block 50) - - F-4F Phantom II - - F-5E Tiger II - - MiG-23MLD Flogger-K - - FC-1 Fierce Dragon - - JF-17 Thunder - - Su-27 Flanker-B - #Senaki, secondary opfor base - 23: - - primary: Transport - - primary: AEW&C diff --git a/resources/campaigns/TheFalconWentOverTheMountain.miz b/resources/campaigns/TheFalconWentOverTheMountain.miz deleted file mode 100644 index a528a436c..000000000 Binary files a/resources/campaigns/TheFalconWentOverTheMountain.miz and /dev/null differ diff --git a/resources/campaigns/TheFalconWentOverTheMountain.yaml b/resources/campaigns/TheFalconWentOverTheMountain.yaml deleted file mode 100644 index 032dbcbe5..000000000 --- a/resources/campaigns/TheFalconWentOverTheMountain.yaml +++ /dev/null @@ -1,447 +0,0 @@ ---- -name: Syria - The Falcon went over the mountain -theater: Syria -authors: Sith1144, updated by Astro -description:

    Campaign about a task force attacking northern Syria from Incirlik. Culling recommended. Do you love SEAD? Know no greater joy in than showing SAMs who truly rules the skies? this is the campaign for you!

    -recommended_player_faction: USA 2005 -recommended_enemy_faction: Syria 2012'ish -recommended_start_date: 2012-06-01 -recommended_player_money: 400 -recommended_enemy_money: 400 -recommended_player_income_multiplier: 1.0 -recommended_enemy_income_multiplier: 1.0 -miz: TheFalconWentOverTheMountain.miz -performance: 2 -version: "11.0" -advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers -#IADS: EWR and C2 get power generators. batteries have their own generators. -iads_config: -# NATO IADS -#EWRs - - NATO EWR-1: - - NATO IADS Command - - NATO EWR: - - NATO IADS Command -# SAMs - - NATO SAM: - - NATO IADS Command - - NATO SAM-1: - - NATO IADS Command - - NATO SAM-2: - - NATO IADS Command - - NATO SAM-3: - - NATO IADS Command - - NATO SAM-4: - - NATO IADS Command - - NATO SAM-5: - - NATO IADS Command - - NATO SAM-6: - - NATO IADS Command - - NATO SAM-7: - - NATO IADS Command -# Yellow defense zone (Gaziantep-Minakh) -#EWRs - - YellowEWRN: #mountainrange (north) - - YellowPPW - - YellowControlN - - YellowEWRS: #mountainrange (center) - - YellowPPW - - YellowControlW - - YellowEWRC: #internal - - HamidiyeControl - - GaziantepControl - - GaziantepPP - - GaziantepAirControl: - - GaziantepControl - - GaziantepPP -# The air defense barrier behind the mountains - - YellowBarrierN: - - YellowControlN - - YellowBarrierC1: - - YellowControlW - - YellowBarrierC2: - - YellowControlW - - YellowBarrierS: - - YellowControlW - - YellowBarrierAAA: - - YellowControlW -# the central long range SAM and its point defenses - - YellowLongRangeSAMPointDefense: - - HamidiyeControl - - YellowLongRangeSAM: - - HamidiyeControl - - YellowLongRangeSAMAAA: - - HamidiyeControl -# the defenses around Gaziantep airfield - - GAZSAMN: - - GaziantepControl - - GAZAAAW: - - GaziantepControl - - GAZSAME: - - GaziantepControl - - GAZAAAE: - - GaziantepControl - - GAZSAMW: - - GaziantepControl - - GaziantepAAA: - - GaziantepControl -# the defenses around Minakh airfield - - MinakhSAM1: - - MinakhControl - - MinakhSAM2: - - MinakhControl - - MinakhAAA: - - MinakhControl -#C2 links - - YellowControlN: - - HamidiyeControl - - YellowControlW: - - HamidiyeControl - - YellowControlN - - YellowZoneCommand: - - GaziantepControl - - MinakhControl - - HamidiyeControl - - GaziantepPP - - GaziantepAirControl -# Green Defense Zone (HATAY) -# EWRs - - CoastalEWRN: - - HatayControl - - AntakyaPower - - CoastalEWRS: - - SamandagControl - - AntakyaPower -# The air defense barrier behind the mountains - - GreenBarrierSAM: - - SamandagControl - - GreenBarrierSAM-1: - - SamandagControl - - GreenBarrierSAM-2: - - HatayControl - - GreenBarrierSAM-3: - - HatayControl - - GreenBarrierSAM-4: - - HatayControl -# Coastal Defenses - - GreenSAM-2: - - SamandagControl - - GreenSAM-3: - - SamandagControl - - GreenSAM-4: - - SamandagControl -# Hatay Airfield - - HataySAM: - - HatayControl - - HataySAM-1: - - HatayControl - - HatayAAA: - - HatayControl -# Industrial/Command zone - - GreenSAM: - - IdlibControl - - GreenZoneCommand - - GreenSAM-2: - - IdlibControl - - GreenZoneCommand -# long range battery and defenses - - GreenZoneSAM: - - ReyhanliControl - - GreenZoneSAMDefense: - - ReyhanliControl -# C2 links - - GreenZoneCommand: - - IdlibControl - - IdlibPower - - SamandagControl - - HatayControl: - - ReyhanliControl - - SamandagControl - - AntakyaPower - - SamandagControl: - - AntakyaPower - - IdlibControl: - - ReyhanliControl - - SamandagControl - - IdlibPower - - ReyhanliControl: - - IdlibPower -# Pink zone (Aleppo) -# EWR - - Abu al-Duhur Air Control: - - Al Safira Power - - Aleppo Air Control: - - Aleppo Power - - Kuweires Air Control: - - Al Safira Power - - Aleppo Power - - Jirah Air Control: - - Al Safira Power -# Aleppo city defenses - - AleppoSAM: - - AleppoCommand - - Aleppo Control - - AleppoSAM-1: - - AleppoCommand - - Aleppo Control - - AleppoSAM-2: - - AleppoCommand - - Aleppo Control - - AleppoSAM-3: - - AleppoCommand - - Aleppo Control - - AleppoSAM-4: - - AleppoCommand - - Aleppo Control - - AleppoSAM-5: - - AleppoCommand - - Aleppo Control - - AleppoSAM-6: - - AleppoCommand - - Aleppo Control - - AleppoSAM-7: - - AleppoCommand - - Aleppo Control -# Long Range SAM - - Pink SAM: - - Al Safira Power - - Aleppo Control - - AlSafiraCommand - - AlSafiraPD: - - Aleppo Control - - AlSafiraCommand -# Abu al-Duhur - - AbuSAM: - - Abu al-Duhur control - - AbuSAM-1: - - Abu al-Duhur control -# Kuweires - - KuweiresSAM: - - KuweiresControl -# Jirah - - JirahSAM: - - JirahControl - - JirahSAM-1: - - JirahControl - - JirahSAM-2: - - JirahControl - - JirahAAA: - - JirahControl -# C2 links - - AleppoCommand: - - Aleppo Power - - Al Safira Power - - Aleppo Control - - AlSafiraCommand: - - Al Safira Power - - Aleppo Power - - Aleppo Control - - KuweiresControl: - - Al Safira Power - - Aleppo Control - - JirahControl: - - Al Safira Power - - KuweiresControl - - Abu al-Duhur control: - - Aleppo Power - - Aleppo Control - - Aleppo Control: - - Aleppo Power -control_points: - From Reserves: - ferry_only: true -squadrons: - #Incirlik (120) - 16: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-15C Eagle - size: 12 - - primary: SEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 12 - - primary: Strike - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 8 - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 8 - - primary: CAS - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 8 - - primary: Strike - secondary: air-to-ground - aircraft: - - F-117A Nighthawk - size: 4 - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 2 - - primary: AEW&C - secondary: any - size: 1 - - primary: Refueling - secondary: any - aircraft: - - KC-135 Stratotanker MPRS - size: 1 - #carrier - Blue Carrier: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14B Tomcat - size: 12 - - primary: BARCAP - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 12 - - primary: AEW&C - secondary: any - size: 1 - - primary: Refueling - secondary: any - size: 2 - #LHA - Blue LHA: - - primary: CAS - secondary: any - aircraft: - - AV-8B Harrier II Night Attack - size: 8 - #Ferry-only - From Reserves: - - primary: SEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 12 - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 3) - size: 12 - # REDFOR squadrons - # Smaller number of modern fighters in forward airfields (Hatay, Minakh and Gaziantep) - # Larger number of older fighters in the rear (Aleppo, Abu Al-Duhur and Jirah) - # CAS aircraft distributed over all airfields, helos more forward - # Aleppo is main airfield for AWACS, Refueling and Transport, for protection it has some modern fighters - #Hatay (10) - 15: - - primary: BARCAP - secondary: any - aircraft: - - MiG-29S Fulcrum-C - size: 4 - - primary: CAS - secondary: any - aircraft: - - Su-25 Frogfoot - size: 4 - - primary: CAS - secondary: any - aircraft: - - Mi-24P Hind-F - size: 2 - #Minakh (20) - 26: - - primary: BARCAP - secondary: any - aircraft: - - Su-30 Flanker-C - size: 8 - - primary: SEAD - secondary: any - aircraft: - - Su-34 Fullback - size: 4 - - primary: Strike - secondary: any - size: 4 - - primary: CAS - secondary: any - aircraft: - - Su-25 Frogfoot - size: 4 - #Gaziantep (12) - 11: - - primary: BARCAP - secondary: any - aircraft: - - MiG-29S Fulcrum-C - size: 4 - - primary: CAS - secondary: any - aircraft: - - Su-25 Frogfoot - size: 4 - - primary: Strike - secondary: any - aircraft: - - Su-24M Fencer-D - size: 4 - #Aleppo (14) - 27: - - primary: BARCAP - secondary: any - aircraft: - - MiG-29S Fulcrum-C - size: 4 - - primary: BARCAP - secondary: any - aircraft: - - MiG-23MLD Flogger-K - size: 4 - - primary: AEW&C - secondary: any - size: 1 - - primary: Refueling - secondary: any - size: 1 - - primary: Transport - secondary: any - size: 2 - #Abu Al-Duhur (36) - 1: - - primary: BARCAP - secondary: any - aircraft: - - MiG-23MLD Flogger-K - size: 12 - - primary: SEAD - secondary: any - aircraft: - - Su-34 Fullback - size: 8 - - primary: Strike - secondary: any - aircraft: - - Su-24M Fencer-D - size: 8 - #Kuweires (37) ID: 31 - #Jirah (28) - 17: - - primary: BARCAP - secondary: any - aircraft: - - MiG-23MLD Flogger-K - size: 12 - - primary: BAI - secondary: any - aircraft: - - Su-24M Fencer-D - size: 8 -# -# air-to-air: Barcap, Tarcap, Escort, and Fighter Sweep \ No newline at end of file diff --git a/resources/campaigns/TheValleyOfRotary.miz b/resources/campaigns/TheValleyOfRotary.miz deleted file mode 100644 index 317875c55..000000000 Binary files a/resources/campaigns/TheValleyOfRotary.miz and /dev/null differ diff --git a/resources/campaigns/TheValleyOfRotary.yaml b/resources/campaigns/TheValleyOfRotary.yaml deleted file mode 100644 index 3e1042ccc..000000000 --- a/resources/campaigns/TheValleyOfRotary.yaml +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: Persian Gulf - Valley of Rotary -theater: Persian Gulf -authors: Sith1144 -description:

    Helicopter-focused counterinsurgency campaign set in Southern Iran. The starting airfield is big and easily supports fixed wing aircraft too.

    -recommended_player_faction: Iran 2015 -recommended_enemy_faction: Insurgents (Hard) -recommended_start_date: 2022-06-13 -recommended_player_money: 800 -recommended_enemy_money: 1000 -miz: TheValleyOfRotary.miz -performance: 2 -version: "10.4" -squadrons: - # Shiraz International, BLUFOR start - 19: - - primary: CAS - aircraft: - - Mi-24P Hind-F - - AH-64D Apache Longbow - - AH-1J SeaCobra - - AH-1W SuperCobra - - primary: CAS - aircraft: - - Mi-24V Hind-E - - UH-1H Iroquois - - A-4E Skyhawk - - AV-8B Harrier II Night Attack - - L-39ZA Albatros - - C-101CC Aviojet - - primary: BAI - aircraft: - - Ka-50 Hokum - - SA 342M Gazelle - - AH-64D Apache Longbow - - Mi-28N Havoc - - primary: Transport - aircraft: - - Mi-8MTV2 Hip - - UH-1H Iroquois - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 3) - - Su-25 Frogfoot - - Su-25T Frogfoot - - A-10A Thunderbolt II - # Jowkan FARP, REDFOR frontline. - Jowkan: - - primary: CAS - # Lar, REDFOR airbase + inverted start - 11: - - primary: CAS - aircraft: - - Mi-24P Hind-F - - Mi-24V Hind-E - - UH-1H Iroquois - - A-4E Skyhawk - - AV-8B Harrier II Night Attack - - L-39ZA Albatros - - C-101CC Aviojet - # Mansurabad, inverted start frontline north - Mansurabad: - - primary: CAS - # Bagh, inverted start frontline south - Bagh: - - primary: Transport diff --git a/resources/campaigns/battle_for_no_mans_land.miz b/resources/campaigns/battle_for_no_mans_land.miz deleted file mode 100644 index 36f3dda81..000000000 Binary files a/resources/campaigns/battle_for_no_mans_land.miz and /dev/null differ diff --git a/resources/campaigns/battle_for_no_mans_land.yaml b/resources/campaigns/battle_for_no_mans_land.yaml deleted file mode 100644 index f049267d1..000000000 --- a/resources/campaigns/battle_for_no_mans_land.yaml +++ /dev/null @@ -1,70 +0,0 @@ ---- -name: Falklands - Battle for No Man's Land -theater: Falklands -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Private Military Company - Russian (Hard) -description: -

    Note: This campaign was designed for helicopters.

    - Set against the rugged and windswept backdrop of the Falkland Islands, - this fictional campaign scenario unfolds with a dramatic dawn sneak attack - on RAF Mount Pleasant Airbase. Orchestrated by a Russia-backed private - military company, the deadly offensive with helicopter gunships and ground troops - has left the airbase's runways in ruins and its defences obliterated. This brutal - incursion resulted in significant casualties among the RAF personnel, with many - killed or wounded in the unexpected onslaught. The carrier HMS Queen Elizabeth and - its task force are on their way to evacuate the survivors and retake Mount Pleasant. - However, they are eight days away at full steam.

    - Amidst this chaos, a beacon of hope emerges in the heart of the Falklands. At Port - Stanley, a small detachment of US military personnel, including helicopter pilots - and armor units, find themselves inadvertently thrust into the fray. Originally at - Port Stanley for some R&R following a training exercise, these soldiers now face - an unexpected and urgent call to action. Their mission is daunting but clear - to - prevent the capture of Port Stanley and liberate East Falkland from the clutches - of the PMC forces.

    - This small group must strategically destroy the PMC forces deployed around the treacherous - valley lying between Wickham Heights and the Onion Ranges, an area ominously known - as No Man's Land. Their plan involves a daring assault to destroy the enemy's - helicopter gunships stationed at San Carlos FOB. Following this, they aim to force - the PMC ground forces into a strategic retreat southward, along the 1.6 mile wide - isthmus into Lafonia. This offensive is designed to create a defensible position - at Goose Green on the narrow isthmus, which can be held against a numerically - superior force until the arrival of Big Lizzie.

    -miz: battle_for_no_mans_land.miz -performance: 1 -recommended_start_date: 2001-11-10 -version: "11.0" -squadrons: - #Port Stanley - 1: - - primary: DEAD - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 6 - - primary: BAI - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 6 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 4 - #San Carlos FOB - 3: - - primary: BAI - secondary: any - aircraft: - - Mi-24P Hind-F - size: 6 - #Goose Green - 24: - - primary: DEAD - secondary: any - aircraft: - - Ka-50 Hokum III - - Ka-50 Hokum (Blackshark 3) - size: 6 \ No newline at end of file diff --git a/resources/campaigns/battle_of_abu_dhabi.miz b/resources/campaigns/battle_of_abu_dhabi.miz deleted file mode 100644 index 2248c6327..000000000 Binary files a/resources/campaigns/battle_of_abu_dhabi.miz and /dev/null differ diff --git a/resources/campaigns/battle_of_abu_dhabi.yaml b/resources/campaigns/battle_of_abu_dhabi.yaml deleted file mode 100644 index 67387a85e..000000000 --- a/resources/campaigns/battle_of_abu_dhabi.yaml +++ /dev/null @@ -1,223 +0,0 @@ ---- -name: Persian Gulf - Battle of Abu Dhabi -theater: Persian Gulf -authors: Colonel Panic -recommended_player_faction: Iran 2015 -recommended_enemy_faction: United Arab Emirates 2015 -description: -

    You have managed to establish a foothold near Ras Al Khaima. Continue - pushing south.

    -miz: battle_of_abu_dhabi.miz -performance: 2 -version: "11.0" -squadrons: - # Blue CPs: - # The default faction is Iran, but the F-14B is given higher precedence so - # that it is used if the faction is something US. The F-14A will be used if - # the player picks some Iran faction that for some reason has carriers. - - # Bandar Abbas: - # This is the main transit hub for blue, so it contains all the logistics-type - # squadrons: airlift, refueling, and AEW&C. It also contains an air-to-air - # squadron for self defense, a bomber squadron, and some air-to-ground - # squadrons. - # - # Due to its location, this will be the primary airbase for the initial phase - # of the campaign. - 2: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-16CM Fighting Falcon (Block 50) - - F-14A Tomcat (Block 135-GR Late) - - primary: DEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - F-14A Tomcat (Block 135-GR Late) - - primary: SEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - primary: AEW&C - size: 2 - aircraft: - - E-3A - - primary: Refueling - size: 2 - aircraft: - - KC-135 Stratotanker - - primary: Transport - size: 4 - aircraft: - - C-17A - - primary: Strike - secondary: air-to-ground - size: 4 - aircraft: - - B-1B Lancer - - Su-24MK Fencer-D - - # Kish: - # This airbase has better access to the theater as the front-line moves south - # west. It contains combat squadrons only. - 24: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-16CM Fighting Falcon (Block 50) - - MiG-29A Fulcrum-A - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - - A-10C Thunderbolt II (Suite 3) - - Su-25 Frogfoot - - primary: BAI - secondary: air-to-ground - size: 8 - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Su-24MK Fencer-D - - primary: DEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Blue CV: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14B Tomcat - - F-14A Tomcat (Block 135-GR Late) - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - - F-14A Tomcat (Block 135-GR Late) - - primary: Strike - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - F-14A Tomcat (Block 135-GR Late) - - primary: BAI - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - F-14A Tomcat (Block 135-GR Late) - - primary: Refueling - size: 2 - aircraft: - - S-3B Tanker - - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - - primary: CAS - size: 8 - secondary: air-to-ground - aircraft: - - UH-1H Iroquois - - SH-60B Seahawk - - # Red CPs: - # Squadrons are designed to work with either UAE 2015 (the default) or a - # typical Russian-sourced aircraft faction. - - # Al Dhafra AFB: - # This CP has factories attached and is the largest red base, so is the main - # logistics hub, with an airlift, AEW&C, and refueling squadron. - # - # For combat this base operates two pure air-to-air squadrons, two pure air- - # to-ground, and four multi-role. Al Minhad is closest to the front so CAS - # squadrons are placed there, but will retreat here after capture. - 4: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Mirage 2000-5 - - Mirage 2000C - - Su-30 Flanker-C - - Su-27 Flanker-B - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-16CM Fighting Falcon (Block 50) - - MiG-31 Foxhound - - MiG-25PD Foxbat-E - - primary: Strike - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Tu-160 Blackjack - - primary: SEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: BAI - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Su-34 Fullback - - Su-24M Fencer-D - - primary: BAI - secondary: any - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: DEAD - secondary: any - - primary: AEW&C - aircraft: - - E-3A - - A-50 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - - IL-78M - - primary: Transport - aircraft: - - C-17A - - IL-78MD - - # Al Minhad AFB: - # The initial front line base. Contains CAS aircraft, as well as an air-to-air - # squadron and an air-to-ground squadron. - 12: - - primary: CAS - secondary: air-to-ground - aircraft: - - AH-64D Apache Longbow - - Mi-24V Hind-E - - Mi-24P Hind-F - - primary: CAS - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Su-25 Frogfoot - - primary: BARCAP - secondary: air-to-air - aircraft: - - Mirage 2000-5 - - Mirage 2000C - - Su-30 Flanker-C - - Su-27 Flanker-B - - primary: BAI - secondary: any - - # Liwa AFB: - # The last-stand base. Contains some factories as well. Begins with only an - # air-to-air squadron. Other squadrons can retreat here as the front-line - # moves. - 29: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Mirage 2000-5 - - Mirage 2000C - - MiG-31 Foxhound - - MiG-25PD Foxbat-E diff --git a/resources/campaigns/black_sea.miz b/resources/campaigns/black_sea.miz deleted file mode 100644 index 85d523a58..000000000 Binary files a/resources/campaigns/black_sea.miz and /dev/null differ diff --git a/resources/campaigns/black_sea.yaml b/resources/campaigns/black_sea.yaml deleted file mode 100644 index f5744f84a..000000000 --- a/resources/campaigns/black_sea.yaml +++ /dev/null @@ -1,168 +0,0 @@ ---- -name: Caucasus - Black Sea -theater: Caucasus -authors: Colonel Panic -description: -

    A medium sized theater with bases along the coast of the Black Sea.

    -recommended_player_faction: USA 2005 -recommended_enemy_faction: Russia 2010 -recommended_start_date: 2004-01-07 -miz: black_sea.miz -performance: 2 -version: "11.0" -squadrons: - # Anapa-Vityazevo - 12: - - primary: BARCAP - aircraft: - - Su-30 Flanker-C - - Su-27 Flanker-B - - primary: AEW&C - aircraft: - - A-50 - size: 2 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - - primary: Transport - aircraft: - - IL-78MD - size: 4 - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-160 Blackjack - size: 4 - # Krasnodar-Center - 13: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-31 Foxhound - - MiG-25PD Foxbat-E - - primary: SEAD - secondary: any - - primary: DEAD - secondary: any - # Maykop-Khanskaya - 16: - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-34 Fullback - - Su-24M Fencer-D - - primary: DEAD - secondary: air-to-ground - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - Mi-24V Hind-E - # Senaki-Kholki - 23: - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - - A-10C Thunderbolt II (Suite 3) - - primary: BAI - secondary: air-to-ground - aircraft: - - F-15E Strike Eagle - - primary: DEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: Transport - aircraft: - - UH-60A - size: 8 - # Kobuleti - 24: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-15C Eagle - - primary: SEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - # Kutaisi - 25: - - primary: BARCAP - aircraft: - - F-15C Eagle - - primary: AEW&C - aircraft: - - E-3A - size: 2 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - size: 2 - - primary: Transport - aircraft: - - C-17A - size: 4 - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 4 - Blue CV: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14B Tomcat - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - - primary: Strike - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: BAI - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: Refueling - aircraft: - - S-3B Tanker - size: 2 - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - - primary: CAS - secondary: air-to-ground - aircraft: - - UH-1H Iroquois - size: 8 - Red CV: - - primary: BARCAP - secondary: air-to-air - - primary: BARCAP - secondary: any - - primary: Strike - secondary: any - - primary: BAI - secondary: any - - primary: Refueling - size: 2 - Red LHA: - - primary: BAI - secondary: air-to-ground - - primary: CAS - secondary: air-to-ground - size: 8 diff --git a/resources/campaigns/caen_to_evreux.miz b/resources/campaigns/caen_to_evreux.miz deleted file mode 100644 index 1ab72101d..000000000 Binary files a/resources/campaigns/caen_to_evreux.miz and /dev/null differ diff --git a/resources/campaigns/caen_to_evreux.yaml b/resources/campaigns/caen_to_evreux.yaml deleted file mode 100644 index fcb8eeaa9..000000000 --- a/resources/campaigns/caen_to_evreux.yaml +++ /dev/null @@ -1,72 +0,0 @@ ---- -name: Normandy - From Caen to Evreux -theater: Normandy -authors: Khopa -description: -

    This is a light scenario on the Normandy map.

    August 1944, allied - forces are pushing from Caen/Carpiquet to the cities of Lisieux and - Evreux.

    Lisieux is an important logistic hub for the Werhmacht, and Evreux - airbase is hosting most of the Luftwaffe forces in the region.

    -recommended_player_faction: Allies 1944 -recommended_enemy_faction: Germany 1944 -recommended_start_date: 1944-07-04 -miz: caen_to_evreux.miz -performance: 1 -version: "11.0" -squadrons: - # Evreux - 26: - - primary: Escort - aircraft: - - Fw 190 D-9 Dora - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Ju 88 A-4 - size: 12 - # Conches - 40: - - primary: BARCAP - secondary: any - aircraft: - - Bf 109 K-4 Kurfürst - size: 4 - # Carpiquet - 19: - - primary: CAS - secondary: any - aircraft: - - Thunderbolt Mk.II (Late) - - P-47D-40 Thunderbolt - size: 12 - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX - size: 12 - - primary: BAI - secondary: air-to-ground - aircraft: - - MosquitoFBMkVI - size: 12 - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - Boston Mk.III - - A-20G Havoc - size: 10 - # Ford_AF - 31: - - primary: Escort - secondary: air-to-air - aircraft: - - Mustang Mk.IV (Early) - - P-51D-25-NA Mustang - size: 10 - - primary: Strike - secondary: air-to-ground - aircraft: - - Fortress Mk.III - - B-17G Flying Fortress - size: 10 diff --git a/resources/campaigns/exercise_bright_star.miz b/resources/campaigns/exercise_bright_star.miz deleted file mode 100644 index 10ce7fb3b..000000000 Binary files a/resources/campaigns/exercise_bright_star.miz and /dev/null differ diff --git a/resources/campaigns/exercise_bright_star.yaml b/resources/campaigns/exercise_bright_star.yaml deleted file mode 100644 index e6eecb520..000000000 --- a/resources/campaigns/exercise_bright_star.yaml +++ /dev/null @@ -1,174 +0,0 @@ ---- -name: Sinai - Exercise Bright Star -theater: Sinai -authors: Starfire -recommended_player_faction: Bluefor Modern -recommended_enemy_faction: Egypt 2000 -description: -

    For over four decades, the United States and Egypt have conducted a series - of biannual joint military exercises known as Bright Star. As the - geopolitical landscape has transformed, so too has the scope and scale of - Exercise Bright Star. The exercise has grown over the years to incorporate - a wide array of international participants. The 2025 iteration of - Exercise Bright Star features eight participating nations alongside - fourteen observer nations.

    - For the 2025 exercises, the United States, along with a select contingent - from the exercise coalition, will take on the role of a hypothetical - adversarial nation, dubbed Orangeland. This scenario is designed to - simulate a mock invasion against Cairo, and presents a valuable - opportunity for participating nations to refine their joint operational - capabilities and improve logistical and tactical interoperability

    - A historic addition to Exercise Bright Star 2025 is the participation of - Israel as an observer nation. This marks a significant milestone, given - the complex historical relations in the region, and symbolises a step - forward in regional collaboration and military diplomacy. Israel's role, - hosting the aggressor faction of the exercise coalition at its airfields, - not only demonstrates the broadening scope of the exercise but also highlights - the value of fostering an environment of mutual cooperation and shared - security objectives.

    -miz: exercise_bright_star.miz -performance: 1 -recommended_start_date: 2025-09-01 -version: "11.0" -squadrons: - Blue CV-1: - - primary: SEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 24 - - primary: AEW&C - aircraft: - - E-2D Advanced Hawkeye - size: 2 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 4 - Bombers from RAF Fairford: - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - size: 8 - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 8 - # Hatzerim (141) - 7: - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 6 - - primary: Escort - secondary: any - aircraft: - - F-15C Eagle - size: 20 - - primary: OCA/Runway - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 16 - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 20 - - primary: BAI - secondary: any - aircraft: - - JF-17 Thunder - size: 16 - - primary: BARCAP - secondary: any - aircraft: - - Mirage 2000C - size: 12 - # Kedem - 12: - - primary: Transport - secondary: any - aircraft: - - CH-47D - size: 20 - - primary: BAI - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 8 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 4 - # Nevatim (106) -# Nevatim temporarilly disabled because airfield is borked -# 8: -# - primary: AEW&C -# aircraft: -# - E-3A -# size: 2 -# - primary: Refueling -# aircraft: -# - KC-135 Stratotanker -# size: 2 - # Melez (30) - 5: - - primary: CAS - secondary: any - aircraft: - - Ka-50 Hokum III - - Ka-50 Hokum (Blackshark 3) - size: 4 - - primary: BAI - secondary: any - aircraft: - - Mirage 2000C - size: 12 - - primary: Escort - secondary: any - aircraft: - - MiG-21bis Fishbed-N - size: 12 - # Wadi al Jandali (72) - 13: - - primary: AEW&C - aircraft: - - E-2C Hawkeye - size: 2 - - primary: SEAD - secondary: any - aircraft: - - F-4E Phantom II - size: 20 - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 20 - - primary: Air Assault - secondary: any - aircraft: - - Mi-24P Hind-F - size: 4 - - primary: OCA/Aircraft - secondary: any - aircraft: - - SA 342L Gazelle - size: 4 - # Cairo West (95) - 18: - - primary: Transport - aircraft: - - C-130 - size: 8 - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - size: 20 \ No newline at end of file diff --git a/resources/campaigns/exercise_vegas_nerve.miz b/resources/campaigns/exercise_vegas_nerve.miz deleted file mode 100644 index 6570446dd..000000000 Binary files a/resources/campaigns/exercise_vegas_nerve.miz and /dev/null differ diff --git a/resources/campaigns/exercise_vegas_nerve.yaml b/resources/campaigns/exercise_vegas_nerve.yaml deleted file mode 100644 index d934df44f..000000000 --- a/resources/campaigns/exercise_vegas_nerve.yaml +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: Nevada - Exercise Vegas Nerve -theater: Nevada -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Redfor (China) 2010 -description: -

    Welcome to Vegas Nerve, an asymmetrical Red Flag Exercise scenario. You are - starting off in control of the two Tonopah airports, and will push south from - there. For the duration of this exercise, Creech AFB has been cleared of all - fixed wing aircraft and will function as a FARP for rotor ops. OPFOR has a - substantial resource advantage and an extensive IADS. Reducing that resource - advantage while degrading their IADS will be vital to a successful completion - of this exercise. Good luck, Commander.

    -miz: exercise_vegas_nerve.miz -performance: 1 -recommended_start_date: 2011-02-24 -version: "11.0" -squadrons: - Bombers from Minot AFB: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - size: 4 - Bombers from Ellsworth AFB: - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 4 - # Tonopah Airport - 17: - - primary: TARCAP - secondary: any - aircraft: - - F-15C Eagle - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 12 - - primary: AEW&C - aircraft: - - E-3A - size: 1 - # Tonopah Test Range - 18: - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 8 - - primary: CAS - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 10 - - primary: DEAD - secondary: air-to-ground - aircraft: - - F/A-18C Hornet (Lot 20) - size: 24 - - primary: SEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 24 - - primary: Air Assault - secondary: air-to-ground - aircraft: - - UH-60L - - UH-60A - size: 2 - # Groom Lake - 2: - - primary: Escort - secondary: air-to-air - aircraft: - - J-11A Flanker-L - size: 20 - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - size: 20 - # Creech - 1: - - primary: CAS - secondary: any - aircraft: - - Ka-50 Hokum III - - Ka-50 Hokum (Blackshark 3) - size: 8 - - primary: Air Assault - secondary: any - aircraft: - - Mi-24P Hind-F - size: 4 - # Nellis AFB - 4: - - primary: Strike - secondary: air-to-ground - aircraft: - - H-6J Badger - size: 20 - - primary: AEW&C - aircraft: - - KJ-2000 - size: 1 - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - size: 20 - - primary: DEAD - secondary: air-to-ground - aircraft: - - Su-34 Fullback - size: 20 - # Boulder City Airport - 6: - - primary: SEAD Escort - secondary: any - aircraft: - - FC-1 Fierce Dragon - size: 20 diff --git a/resources/campaigns/final_countdown_2.miz b/resources/campaigns/final_countdown_2.miz deleted file mode 100644 index 835d69f5d..000000000 Binary files a/resources/campaigns/final_countdown_2.miz and /dev/null differ diff --git a/resources/campaigns/final_countdown_2.yaml b/resources/campaigns/final_countdown_2.yaml deleted file mode 100644 index 1b1fa38e5..000000000 --- a/resources/campaigns/final_countdown_2.yaml +++ /dev/null @@ -1,136 +0,0 @@ ---- -name: Normandy - The Final Countdown II -theater: Normandy -authors: Starfire -recommended_player_faction: D-Day Allied Forces 1944 and 1990 -recommended_enemy_faction: Germany 1944 -description: -

    While enroute to the Persian Gulf for Operation Desert Shield, the USS - Theodore Roosevelt and its carrier strike group are engufled by an electrical - vortex and transported through time and space to the English channel on the - morning of the Normandy Landings - June 6th 1944. Seeking to reduce the cost - in lives to the Allied Forces about to storm the beaches, the captain of the - Roosevelt has elected to provide air support for the - landings.

    Note: This campaign has a custom faction that - combines modern US naval forces with WW2 Allied forces. To play it as - intended, you should carefully ration your use of modern aircraft and not - replenish them if shot down (as you cannot get new Tomcats and Hornets in - 1944). You can also choose to play it as a purely WW2 campaign by switching to - one of the WW2 Ally factions.

    -miz: final_countdown_2.miz -performance: 2 -recommended_start_date: 1944-06-06 -version: "11.0" -squadrons: - #Blue CV (90) - Blue-CV: - - primary: TARCAP - secondary: any - aircraft: - - F-14B Tomcat - size: 24 - - primary: DEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 24 - - primary: CAS - secondary: air-to-ground - aircraft: - - S-3B Viking - size: 12 - - primary: AEW&C - aircraft: - - E-2C Hawkeye - size: 2 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 2 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 6 - #Stoney Cross (39) - 58: - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - A-20G Havoc - - Boston Mk.III - size: 20 - #Needs Oar Point (55) - 28: - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX - size: 20 - - primary: DEAD - secondary: air-to-ground - aircraft: - - MosquitoFBMkVI - size: 20 - #RAF Grafton Underwood (1000) - Bombers from RAF Grafton Underwood: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-17G Flying Fortress - - Fortress Mk.III - size: 20 - #Lymington (56) - 37: - - primary: Escort - secondary: any - aircraft: - - P-51D-30-NA Mustang - - Mustang Mk.IV (Late) - size: 20 - - primary: BAI - secondary: any - aircraft: - - P-47D-40 Thunderbolt - - Thunderbolt Mk.II (Late) - size: 20 - - #Carpiquet (47) - 19: - - primary: TARCAP - secondary: air-to-air - aircraft: - - Fw 190 D-9 Dora - size: 12 - - primary: CAS - secondary: air-to-ground - aircraft: - - Ju 88 A-4 - size: 8 - #Broglie (32) - 68: - - primary: Escort - secondary: any - aircraft: - - Bf 109 K-4 Kurfürst - size: 24 - #Saint-Andre-de-lEure (30) - 70: - - primary: BAI - secondary: air-to-ground - aircraft: - - Ju 88 A-4 - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Ju 88 A-4 - size: 12 - #Vilacoublay (76) - 42: - - primary: BARCAP - secondary: any - aircraft: - - Fw 190 A-8 Anton - size: 20 \ No newline at end of file diff --git a/resources/campaigns/golan_heights_lite.miz b/resources/campaigns/golan_heights_lite.miz deleted file mode 100644 index 4957ffd9f..000000000 Binary files a/resources/campaigns/golan_heights_lite.miz and /dev/null differ diff --git a/resources/campaigns/golan_heights_lite.yaml b/resources/campaigns/golan_heights_lite.yaml deleted file mode 100644 index 2106f9368..000000000 --- a/resources/campaigns/golan_heights_lite.yaml +++ /dev/null @@ -1,204 +0,0 @@ ---- -name: Syria - Battle for Golan Heights -theater: Syria -authors: Khopa -recommended_player_faction: Israel 2000 -recommended_enemy_faction: Syria 2011 -description: -

    In this scenario, you start in Israel and the conflict is focused around - the golan heights, an historically disputed territory.

    This scenario - is designed to be performance and helicopter friendly.

    -miz: golan_heights_lite.miz -performance: 1 -version: "11.0" -advanced_iads: true # Campaign has connection_nodes / power_sources / command_centers -iads_config: - - LHA-1 Tarawa # A Naval Group without connections but still participating as EWR - - Naval-2 # 2 Ship as EWR - - CVN-74 John Stennis # Aircraft Carrier as EWR - - Golan North-100: - - IADS_CN2 - - IADS_PS4 - - IADS_PS3 - - Golan North-11: - - IADS_CN2 - - IADS_PS3 - - Golan North-139: - - IADS_PS2 - - IADS_CN6 - - Golan North-15: - - IADS_PS5 - - IADS_PS6 - - IADS_CN3 - - IADS_CN1 - - Golan North-150: - - IADS_PS2 - - IADS_CN1 - - IADS_CN6 - - Golan North-158: - - IADS_PS6 - - IADS_CN1 - - Golan North-159: - - IADS_PS3 - - IADS_CN4 - - Golan North-17: - - IADS_PS4 - - IADS_CN7 - - IADS_CN5 - - Golan North-5: - - IADS_PS3 - - IADS_CN4 - - Golan North-6: - - IADS_PS3 - - IADS_CN4 - - Golan North-74: - - IADS_PS6 - - IADS_CN1 - - Golan North-81: - - IADS_PS1 - - IADS_CN6 - - IADS_CN8 - - Golan North-84: - - IADS_PS2 - - IADS_CN6 - - Golan North-88: - - IADS_PS6 - - IADS_PS2 - - IADS_CN1 - - IADS_CN6 - - IADS_CN8 - - Golan North-9: - - IADS_PS1 - - IADS_CN8 - - Golan North-99: - - IADS_PS4 - - IADS_CN7 - - IADS_CN2 - - Golan North-146: - - IADS_PS2 - - IADS_CN6 - - Golan North-52: - - IADS_PS5 - - IADS_CN3 - - IADS_CN5 - - Golan North-118: - - IADS_PS3 - - IADS_CN4 - - Golan North-119: - - IADS_PS4 - - IADS_CN7 - - IADS_CN5 - - Golan North-122: - - IADS_PS2 - - IADS_CN6 - - IADS Blue Command Center: - - IADS_PS3 - - IADS_CN4 - - IADS_CN2 - - IADS Red Command Center: - - IADS_PS1 - - IADS_CN6 - - IADS_CN8 -squadrons: - # Ramat-David - 30: - - primary: AEW&C - aircraft: - - E-3A - size: 1 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - size: 1 - - primary: Escort - secondary: air-to-air - aircraft: - - F-15C Eagle - size: 10 - - primary: BARCAP - secondary: any - aircraft: - - F-4E Phantom II - size: 10 - - primary: Strike - secondary: air-to-ground - aircraft: - - F-15E Strike Eagle - size: 10 - - primary: SEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 10 - # Golan South - Golan South: - - primary: CAS - secondary: air-to-ground - nickname: Golan Heights Heroes - female_pilot_percentage: 15 - aircraft: - - AH-1W SuperCobra - size: 4 - - primary: BAI - secondary: air-to-ground - nickname: Defenders of Golan - female_pilot_percentage: 25 - aircraft: - - AH-64D Apache Longbow - size: 6 - - primary: Air Assault - secondary: any - aircraft: - - UH-1H Iroquois - size: 2 - # Golan North - Golan North: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - size: 4 - - primary: Air Assault - secondary: any - aircraft: - - Mi-8MTV2 Hip - size: 2 - # Marj Ruhayyil - 23: - - primary: BAI - secondary: any - aircraft: - - MiG-21bis Fishbed-N - size: 12 - - primary: Escort - secondary: any - aircraft: - - MiG-21bis Fishbed-N - size: 12 - # Damascus - 7: - - primary: BARCAP - secondary: any - aircraft: - - MiG-23MLD Flogger-K - size: 12 - - primary: TARCAP - secondary: any - aircraft: - - MiG-25PD Foxbat-E - size: 12 - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-17M4 Fitter-K - size: 12 diff --git a/resources/campaigns/grabthars_hammer.miz b/resources/campaigns/grabthars_hammer.miz deleted file mode 100644 index 06af6fa5f..000000000 Binary files a/resources/campaigns/grabthars_hammer.miz and /dev/null differ diff --git a/resources/campaigns/grabthars_hammer.yaml b/resources/campaigns/grabthars_hammer.yaml deleted file mode 100644 index 6b1c46457..000000000 --- a/resources/campaigns/grabthars_hammer.yaml +++ /dev/null @@ -1,161 +0,0 @@ ---- -name: Falklands - Operation Grabthar's Hammer -theater: Falklands -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Russia 2010 -description: -

    An Argentinean extremist group has contracted the Sons of Warvan (SoW), an - unusually well-equipped PMC with close ties to the Russian government, to - construct a beryllium bomb at the secret Omega 13 production facility in - Ushuaia for use in its ongoing conflict with Chile. United States military - forces have established a foothold at San Julian. While the SoW are distracted - up north, it is up to the Marines to launch an assault upon Ushuaia from an LHA - in order to disable the bomb production facility. Fortunately, Ushuaia is - lightly defended as the SoW are trying to avoid unwanted attention.

    -miz: grabthars_hammer.miz -performance: 2 -recommended_start_date: 1999-12-25 -version: "11.0" -squadrons: - #Mount Pleasant - 2: - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 8 - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 8 - - primary: Escort - secondary: any - aircraft: - - F-15C Eagle - size: 8 - - primary: CAS - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 8 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - size: 2 - #San Julian - 11: - - primary: BAI - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 8 - #Blue CV - Blue-CV: - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - size: 20 - - primary: SEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 40 - - primary: DEAD - secondary: air-to-ground - aircraft: - - S-3B Viking - size: 20 - - primary: AEW&C - aircraft: - - E-2C Hawkeye - size: 2 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 4 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 4 - # Blue LHA - Blue-LHA: - - primary: DEAD - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - size: 18 - - primary: Air Assault - secondary: any - aircraft: - - UH-1H Iroquois - size: 2 - Bombers from Edwards AFB: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - size: 12 - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 12 - #El Calafate - 14: - - primary: Transport - aircraft: - - Mi-8MTV2 Hip - size: 10 - #Rio Gallegros - 5: - - primary: Escort - secondary: air-to-air - aircraft: - - Su-27 Flanker-B - size: 12 - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - size: 12 - #Punta Arenas - 9: - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - size: 16 - - primary: DEAD - secondary: air-to-ground - aircraft: - - Su-34 Fullback - size: 16 - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-22M3 Backfire-C - size: 16 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - #Ushuaia - 7: - - primary: CAS - secondary: any - aircraft: - - Ka-50 Hokum III - - Ka-50 Hokum (Blackshark 3) - size: 8 - #Ushuaia Helo Port - 8: - - primary: Air Assault - secondary: any - aircraft: - - Mi-24P Hind-F - size: 8 diff --git a/resources/campaigns/gran_polvorin.miz b/resources/campaigns/gran_polvorin.miz deleted file mode 100644 index 67ea84290..000000000 Binary files a/resources/campaigns/gran_polvorin.miz and /dev/null differ diff --git a/resources/campaigns/gran_polvorin.yaml b/resources/campaigns/gran_polvorin.yaml deleted file mode 100644 index 74b674084..000000000 --- a/resources/campaigns/gran_polvorin.yaml +++ /dev/null @@ -1,131 +0,0 @@ ---- -name: Falklands - Gran Polvorin -theater: Falklands -authors: Fuzzle -description: -

    A naval campaign where a US carrier group must fight through Argentina and - Chile to repel Chinese invaders. This is a purely naval campaign, - meaning you will need to use the Air Assault mission type with transports to - take the first FOB. Ensure you soften it up enough - first!

    Backstory: As war explodes around the - Pacific Rim, a Chinese battle group breaks through the blockade and makes for - South America, looking to establish bases within striking distance of the US' - southern allies. To avoid follow-on PLAN forces should they break through the - fighting to the west, a USN battle group is dispatched from the east coast of - the US to clear the Chinese forces from the continent and crush their carrier - group.

    -version: "11.0" -recommended_player_faction: US Navy 2005 -recommended_enemy_faction: China 2010 -miz: gran_polvorin.miz -performance: 2 -recommended_start_date: 2006-05-12 -recommended_player_money: 1000 -recommended_enemy_money: 1500 -recommended_player_income_multiplier: 1.3 -recommended_enemy_income_multiplier: 0.6 -squadrons: - #BLUFOR CVN - Naval-2: - - primary: BARCAP - secondary: any - aircraft: - - VF-143 - size: 14 - - primary: SEAD - secondary: air-to-ground - aircraft: - - VMFA-251 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - # BLUFOR LHA - Naval-3: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-169 (AH-1W) - size: 6 - # OPFOR CVN - Naval-1: - - primary: BARCAP - secondary: any - aircraft: - - J-15 Flanker X-2 - - primary: Strike - secondary: any - aircraft: - - J-15 Flanker X-2 - # OPFOR First FOB - FOB Dinero: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # Rio Gallegos - 5: - - primary: BARCAP - secondary: any - aircraft: - - FC-1 Fierce Dragon - # OPFOR Second FOB - FOB Vista: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR Third FOB - FOB Galy: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # Punta Arenas - 9: - - primary: TARCAP - secondary: air-to-air - aircraft: - - J-11A Flanker-L - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - H-6J Badger - # Rio Gallegos - 7: - - primary: BARCAP - secondary: any - aircraft: - - J-7B - size: 6 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - H-6J Badger - size: 2 \ No newline at end of file diff --git a/resources/campaigns/northern_russia.miz b/resources/campaigns/northern_russia.miz deleted file mode 100644 index 46a10e22c..000000000 Binary files a/resources/campaigns/northern_russia.miz and /dev/null differ diff --git a/resources/campaigns/northern_russia.yaml b/resources/campaigns/northern_russia.yaml deleted file mode 100644 index fb8ba613b..000000000 --- a/resources/campaigns/northern_russia.yaml +++ /dev/null @@ -1,197 +0,0 @@ ---- -name: Caucasus - Northern Russia -theater: Caucasus -authors: Plob -description:

    A medium campaign through the north eastern part of the Caucasus map.

    Russia has invaded Georgia through the eastern mountains. Mount a counter offense and push them back!

    -recommended_player_faction: Bluefor Modern -recommended_enemy_faction: Russia 1975 -recommended_start_date: 1995-06-13 -miz: northern_russia.miz -performance: 2 -version: "10.5" -squadrons: - # Kutaisi - 25: - - primary: Refueling - aircraft: - - KC-135 Stratotanker MPRS - - primary: Refueling - aircraft: - - KC-135 Stratotanker - - primary: AEW&C - aircraft: - - E-3A - - primary: Transport - secondary: any - aircraft: - - C-130 - - primary: Strike - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: BAI - secondary: air-to-ground - aircraft: - - AH-64D Apache Longbow - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 3) - - primary: BARCAP - secondary: any - aircraft: - - JF-17 Thunder - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: BAI - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - - primary: Strike - secondary: any - aircraft: - - AJS-37 Viggen - - primary: Strike - secondary: any - aircraft: - - Mirage 2000C - - primary: CAS - secondary: air-to-ground - aircraft: - - UH-1H Iroquois - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - # Tbilisi-Lochini - 29: - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BARCAP - aircraft: - - MiG-29A Fulcrum-A - - primary: BAI - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - # Beslan - 32: - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BAI - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - - primary: Strike - aircraft: - - Su-25 Frogfoot - - primary: BAI - aircraft: - - Su-25 Frogfoot - # Mozdok - 28: - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BAI - aircraft: - - Su-25 Frogfoot - - primary: Strike - aircraft: - - Tu-95MS Bear-H - - primary: SEAD - aircraft: - - Su-17M4 Fitter-K - - primary: Strike - aircraft: - - Su-17M4 Fitter-K - # Nalchik - 27: - - primary: BARCAP - aircraft: - - MiG-25PD Foxbat-E - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BARCAP - aircraft: - - MiG-29A Fulcrum-A - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - # Mineralnye Vody - 26: - - primary: BARCAP - aircraft: - - MiG-25PD Foxbat-E - - primary: BARCAP - aircraft: - - MiG-21bis Fishbed-N - - primary: BARCAP - aircraft: - - MiG-25PD Foxbat-E - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: Strike - aircraft: - - Su-25 Frogfoot - - primary: AEW&C - aircraft: - - A-50 - - primary: Refueling - aircraft: - - IL-78M - Blue CV: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14B Tomcat - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - - primary: Strike - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: BAI - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: Refueling - aircraft: - - S-3B Tanker - - primary: AEW&C - aircraft: - - E-2C Hawkeye - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack diff --git a/resources/campaigns/operation_aegean_aegis.miz b/resources/campaigns/operation_aegean_aegis.miz deleted file mode 100644 index b7d925253..000000000 Binary files a/resources/campaigns/operation_aegean_aegis.miz and /dev/null differ diff --git a/resources/campaigns/operation_aegean_aegis.yaml b/resources/campaigns/operation_aegean_aegis.yaml deleted file mode 100644 index da989d365..000000000 --- a/resources/campaigns/operation_aegean_aegis.yaml +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: Syria - Operation Aegean Aegis -theater: Syria -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Turkey 2005 -description: -

    Note: This fictional campaign was designed for the Apache - and Harrier. It requires manual flight planning. While enemy aircraft are present - at airfields, there will be no enemy flights as their aircraft are grounded.

    -

    - In a sudden and alarming escalation of tensions in Cyprus, the Anatolian Order, - a North Cypriot insurgent faction, has carried out a bold night-time assault on - three crucial airfields in the Republic of Cyprus; Paphos, Akrotiri, and Larnaca. - The insurgents, equipped with stolen surplus Turkish military hardware, used - chemical weapons in their attack, forcing the evacuation of all three airfields. - Notably, the capture of Akrotiri, a British Overseas Territory hosting a Royal - Air Force base, has drawn significant international attention and concern.

    -

    - The EU has strongly condemned this unprovoked attack against one of its member - states. Turkey, despite its historical connections with North Cyprus, has also - denounced the Anatolian Order's actions and is investigating how its aircraft, - ground vehicles, and weaponry held in storage ended up in insurgent hands.

    -

    - Amidst the crisis, a lone US Navy LHA, strategically positioned in the Aegean Sea, - is preparing a response to the crisis. Its mission is to deploy Apache helicopters - to neutralise the hastily erected air defenses around the captured airfields, before - Harrier jumpjets neutralise the Anatolian Order's aircraft. These aircraft, a - selection of mothballed Turkish F-4s and helicopters, are currently grounded due to - lack of suitable fuel and spare parts. It is imperative that they are dealt with - swiftly before ground troops are air-lifted in to reclaim the airfields.

    -

    - The operation's final phase involves targeting North Cyprus's only airport at Ercan. - The plan is to bomb its runway, preventing any further airborne reinforcements by the - insurgents. However, due to the air defenses established along the northern edge of - the Green Line (the UN-patrolled demilitarised zone) there are strict advisories against - overflying North Cyprus unless absolutely necessary, to minimise the risk of losses. -

    -miz: operation_aegean_aegis.miz -performance: 1 -recommended_start_date: 2017-04-20 -recommended_player_money: 1000 -recommended_enemy_money: 0 -recommended_player_income_multiplier: 1.0 -recommended_enemy_income_multiplier: 0.0 -version: "11.0" -squadrons: - #Tarawa Class LHA - Blue-LHA: - - primary: DEAD - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 12 - - primary: DEAD - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - size: 6 - - primary: Air Assault - secondary: any - aircraft: - - UH-1H Iroquois - size: 2 - #Paphos - 46: - - primary: DEAD - secondary: air-to-ground - aircraft: - - F-4E Phantom II - size: 12 - #Akrotiri - 44: - - primary: BAI - secondary: any - aircraft: - - AH-1W SuperCobra - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - OH-58D Kiowa Warrior - size: 4 - - primary: Transport - secondary: any - aircraft: - - UH-60A - size: 4 - #Larnaca - 47: - - primary: Transport - aircraft: - - C-130 - size: 6 - #Ercan - 49: - - primary: Transport - secondary: any - aircraft: - - CH-47D - size: 6 diff --git a/resources/campaigns/operation_allied_sword.miz b/resources/campaigns/operation_allied_sword.miz deleted file mode 100644 index bc153c3c4..000000000 Binary files a/resources/campaigns/operation_allied_sword.miz and /dev/null differ diff --git a/resources/campaigns/operation_allied_sword.yaml b/resources/campaigns/operation_allied_sword.yaml deleted file mode 100644 index ca833cf44..000000000 --- a/resources/campaigns/operation_allied_sword.yaml +++ /dev/null @@ -1,413 +0,0 @@ ---- -name: Syria - Operation Allied Sword -theater: Syria -authors: Fuzzle -recommended_player_faction: - country: Combined Joint Task Forces Blue - name: Israel-USN 2005 - authors: Fuzzle - description: -

    A joint US Navy/Israeli modern faction for use with the Operation Allied - Sword scenario.

    - locales: - - en_US - aircrafts: - - F-4E Phantom II - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-14B Tomcat - - F/A-18C Hornet (Lot 20) - - AV-8B Harrier II Night Attack - - AH-1W SuperCobra - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois - - UH-60L - awacs: - - E-2C Hawkeye - tankers: - - KC-130 - - S-3B Tanker - frontline_units: - - M113 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - Merkava Mk IV - - M163 Vulcan Air Defense System - artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System - logistics_units: - - Truck M818 6x6 - infantry_units: - - Infantry M4 - - Infantry M249 - - MANPADS Stinger - preset_groups: - - Hawk - - Patriot - naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis - missiles: [] - air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral - requirements: {} - carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman - helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu - has_jtac: true - jtac_unit: MQ-9 Reaper - doctrine: modern - liveries_overrides: - F-14B Tomcat: - - VF-142 Ghostriders - F/A-18C Hornet (Lot 20): - - VMFA-251 high visibility - AV-8B Harrier II Night Attack: - - VMAT-542 - AH-1W SuperCobra: - - Marines - UH-1H Iroquois: - - US NAVY - UH-60L: - - Israeli Air Force - unrestricted_satnav: true -recommended_enemy_faction: - country: Combined Joint Task Forces Red - name: Syria-Lebanon 2005 (Allied Sword) - authors: Fuzzle - description: -

    Syria-Lebanon alliance in a modern setting with several imported Russian - assets. Designed for use with the Allied Sword scenario.

    - aircrafts: - - MiG-23ML Flogger-G - - MiG-25RBT Foxbat-B - - MiG-29A Fulcrum-A - - Su-17M4 Fitter-K - - Su-24M Fencer-D - - Su-30 Flanker-C - - Su-34 Fullback - - L-39ZA Albatros - - Tu-22M3 Backfire-C - - Mi-24V Hind-E - - Mi-8MTV2 Hip - - SA 342M Gazelle - - SA 342L Gazelle - - IL-76MD - awacs: - - A-50 - tankers: - - IL-78M - frontline_units: - - BMP-1 - - BMP-2 - - BTR-80 - - BRDM-2 - - MT-LB - - T-55A - - T-72B with Kontakt-1 ERA - - T-90A - - ZSU-57-2 'Sparka' - artillery_units: - - BM-21 Grad - - 2S1 Gvozdika - logistics_units: - - Truck Ural-375 - - LUV UAZ-469 Jeep - infantry_units: - - Paratrooper AKS - - Infantry AK-74 Rus - - Paratrooper RPG-16 - - MANPADS SA-18 Igla-S "Grouse" - preset_groups: - - SA-2/S-75 - - SA-3/S-125 - - SA-6 - - SA-11 - - SA-10/S-300PS - - Silkworm - - Cold-War-Flak - - Russian Navy - naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya - - FAC La Combattante IIa - - Frigate 1135M Rezky - air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - EWR 1L13 - - EWR 55G6 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-19 Grison (2K22 Tunguska) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka - missiles: - - SSM SS-1C Scud-B - helicopter_carrier_names: [] - requirements: {} - carrier_names: [] -description: -

    In this fictional scenario, a US/Israeli coalition must push north from the - Israeli border, through Syria and Lebanon to - Aleppo.

    Backstory: A Syrian-Lebanese joint force (with - Russian materiel support) has attacked Israel, attmepting to cross the - northern border. With the arrival of a US carrier group, Israel prepares its - counterattack. The US Navy will handle the Beirut region's coastal arena, - while the IAF will push through Damascus and the inland mountain ranges.

    -version: "11.0" -miz: operation_allied_sword.miz -performance: 2 -recommended_start_date: 2004-07-17 -recommended_player_money: 1200 -recommended_enemy_money: 1500 -recommended_player_income_multiplier: 1.0 -recommended_enemy_income_multiplier: 0.5 -squadrons: - #BLUFOR CVN - Naval-1: - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-143 - size: 14 - - primary: SEAD - secondary: any - aircraft: - - VFA-192 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - #BLUFOR LHA - Naval-3: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-214 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-269 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-269 (AH-1W) - size: 6 - # OPFOR CVN - Naval-2: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-33 Flanker-D - - primary: TARCAP - secondary: air-to-ground - aircraft: - - Su-33 Flanker-D - # OPFOR LHA - Naval-4: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 6 - #Haifa - 13: - - primary: CAS - secondary: air-to-ground - aircraft: - - 113th Squadron - #Ramat David - 30: - - primary: BARCAP - secondary: air-to-air - aircraft: - - 106th Squadron - - primary: SEAD - secondary: any - aircraft: - - 201th Squadron - - primary: Refueling - aircraft: - - VMGR-352 - size: 2 - - primary: Strike - secondary: any - aircraft: - - 69th Squadron - size: 8 - - primary: BAI - secondary: any - aircraft: - - 110th Squadron - size: 8 - # Damascus - 7: - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - - primary: CAS - secondary: air-to-ground - aircraft: - - L-39ZA Albatros - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-17M4 Fitter-K - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342L Gazelle - # Beirut-Rafic Hariri - 6: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-17M4 Fitter-K - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342L Gazelle - # OPFOR First inland FOB - FOB Al Quaryatayn: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - size: 6 - # OPFOR Second inland FOB - FOB Homs: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - size: 6 - # Palmyra - 28: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - size: 10 - # Bassel Al-Assad - 21: - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-23ML Flogger-G - - primary: BARCAP - secondary: any - aircraft: - - MiG-29A Fulcrum-A - - primary: Refueling - aircraft: - - IL-78M - size: 1 - - primary: Transport - aircraft: - - IL-76MD - size: 1 - - primary: AEW&C - aircraft: - - A-50 - size: 1 - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-22M3 Backfire-C - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - # OPFOR Second inland FOB - FOB Ithriyah: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 6 - # OPFOR Second coastal FOB - FOB Samandag: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 6 - # Aleppo - 27: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-30 Flanker-C - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 8 - # Kuweires - 31: - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-23ML Flogger-G - - primary: BARCAP - secondary: any - aircraft: - - MiG-29A Fulcrum-A - size: 8 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-34 Fullback - - primary: Transport - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - size: 2 diff --git a/resources/campaigns/operation_blackball.miz b/resources/campaigns/operation_blackball.miz deleted file mode 100644 index b73a9811c..000000000 Binary files a/resources/campaigns/operation_blackball.miz and /dev/null differ diff --git a/resources/campaigns/operation_blackball.yaml b/resources/campaigns/operation_blackball.yaml deleted file mode 100644 index 9073b8bbb..000000000 --- a/resources/campaigns/operation_blackball.yaml +++ /dev/null @@ -1,160 +0,0 @@ ---- -name: Syria - Operation Blackball -theater: Syria -authors: Fuzzle -description:

    A lightweight fictional showcase of Cyprus for the Syria terrain. A US Navy force must deploy from a carrier group to push through the island. This is a purely naval campaign, meaning you will need to use the Air Assault mission type with transports to take the first FOB. Ensure you soften it up enough first!

    Backstory: The world is at war. With the help of her eastern allies Russia has taken the Suez Canal and deployed a large naval force to the Mediterranean, trapping a US carrier group near the Turkish-Syrian border. Now they must break out by taking Cyprus back.

    -version: "11.0" -recommended_player_faction: US Navy 2005 -recommended_enemy_faction: Russia 2010 -miz: operation_blackball.miz -performance: 1 -recommended_start_date: 2006-05-17 -recommended_player_money: 1000 -recommended_enemy_money: 1200 -recommended_player_income_multiplier: 1.1 -recommended_enemy_income_multiplier: 0.7 -squadrons: - # BLUFOR CVN - Naval-1: - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-142 - size: 14 - - primary: SEAD - secondary: air-to-ground - aircraft: - - VFA-106 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - # BLUFOR LHA - Naval-2: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-269 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-269 (AH-1W) - size: 6 - # OPFOR Start FOB - FOB Andreas: - - primary: CAS - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - size: 6 - # OPFOR CVN - Naval-3: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-33 Flanker-D - - primary: TARCAP - secondary: air-to-ground - aircraft: - - Su-33 Flanker-D - # OPFOR LHA - Naval-4: - - primary: CAS - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - size: 6 - # Larnaca - 47: - - primary: TARCAP - secondary: any - aircraft: - - MiG-29S Fulcrum-C - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - # Akrotiri - 44: - - primary: BARCAP - secondary: any - aircraft: - - Su-27 Flanker-B - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-34 Fullback - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-95MS Bear-H - # Paphos - 46: - - primary: BARCAP - secondary: any - aircraft: - - Su-30 Flanker-C - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-34 Fullback - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-160 Blackjack - size: 6 - - primary: AEW&C - aircraft: - - A-50 - size: 1 - - primary: Refueling - aircraft: - - IL-78M - size: 1 - - primary: Transport - aircraft: - - IL-78MD - size: 1 - # OPFOR First FOB - FOB Gecitkale: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR Second FOB - FOB Guzelyurt: - - primary: Transport - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - size: 2 - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 4 \ No newline at end of file diff --git a/resources/campaigns/operation_dynamo.miz b/resources/campaigns/operation_dynamo.miz deleted file mode 100644 index cfd68ffbe..000000000 Binary files a/resources/campaigns/operation_dynamo.miz and /dev/null differ diff --git a/resources/campaigns/operation_dynamo.yaml b/resources/campaigns/operation_dynamo.yaml deleted file mode 100644 index d481224db..000000000 --- a/resources/campaigns/operation_dynamo.yaml +++ /dev/null @@ -1,54 +0,0 @@ -name: "The Channel - Operation Dynamo" -theater: "The Channel" -authors: "Khopa" -recommended_player_faction: "Allies 1940" -recommended_enemy_faction: "Germany 1940" -description: "

    The Battle of Dunkirk (French: Bataille de Dunkerque) was fought around the French port of Dunkirk (Dunkerque) during the Second World War, between the Allies and Nazi Germany. As the Allies were losing the Battle of France on the Western Front, the Battle of Dunkirk was the defence and evacuation of British and other Allied forces to Britain from 26 May to 4 June 1940..

    " -miz: "operation_dynamo.miz" -performance: 1 -version: "10.0" -squadrons: - # Manston - 5: - - primary: Strike - secondary: any - aircraft: - - Boston Mk.III - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX - # Hawkinge - 6: - - primary: Strike - secondary: any - aircraft: - - MosquitoFBMkVI - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX (Clipped Wings) - # Dunkirk Mardyck - 4: - - primary: BARCAP - secondary: any - aircraft: - - Spitfire LF Mk IX - # St Omer - 3: - - primary: BARCAP - secondary: any - aircraft: - - Bf 109 K-4 Kurfürst - - primary: BARCAP - secondary: any - aircraft: - - Fw 190 A-8 Anton - - primary: Strike - secondary: any - aircraft: - - Ju 88 A-4 diff --git a/resources/campaigns/operation_noisy_cricket.miz b/resources/campaigns/operation_noisy_cricket.miz deleted file mode 100644 index 78096bea7..000000000 Binary files a/resources/campaigns/operation_noisy_cricket.miz and /dev/null differ diff --git a/resources/campaigns/operation_noisy_cricket.yaml b/resources/campaigns/operation_noisy_cricket.yaml deleted file mode 100644 index ebe6946d4..000000000 --- a/resources/campaigns/operation_noisy_cricket.yaml +++ /dev/null @@ -1,147 +0,0 @@ ---- -name: Persian Gulf - Operation Noisy Cricket -theater: Persian Gulf -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Iran 2015 -description: -

    In the face of mounting sanctions against their nuclear program, Iran has - barred all shipping from transiting the Strait of Hormuz. Three days ago, the - Iranian Vice-President ordered a series of missile attacks on commercial - vessels entering the Gulf of Oman through the highly strategic chokepoint, - sinking a container ship and damaging two oil tankers. Operation Noisy Cricket - is the American response to this threat to regional stability. The objective - is to render inoperative Iran's array of coastal anti-ship missile sites, as - well as disable the airfields from which maritime strike aircraft could be - launched.

    While officially intended only to deter any further attempts - to disrupt the flow of maritime traffic and and protect the interests of the - global economy, The USAF will also leverage the resultant degradation in - Iranian air defences to launch a deep strike from airfields in the UAE in an - attempt to take out Iran's last combat-worthy F-14 Tomcats, currently - stationed at Kerman. At the same time, a carrier-based Marine detachment will - be inserted via helicopter to conduct an unscheduled inspection of the Bushehr - Nuclear Power Plant, in order to verify Iran's compliance with international - nuclear agreements and gather evidence of any ongoing nuclear weapons - development.

    -miz: operation_noisy_cricket.miz -performance: 1 -recommended_start_date: 2019-07-13 -recommended_player_money: 0 -recommended_enemy_money: 0 -recommended_player_income_multiplier: 0.2 -recommended_enemy_income_multiplier: 0.2 -version: "11.0" -squadrons: - Blue CV-1: - - primary: SEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 40 - - primary: AEW&C - aircraft: - - E-2D Advanced Hawkeye - size: 2 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 4 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 4 - #Al Minhad AFB (61) - 12: - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 32 - - primary: Escort - secondary: air-to-air - aircraft: - - F-15C Eagle - size: 24 - #Al Dhafra AFB (251) - 4: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 4 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - size: 1 - - primary: OCA/Runway - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 20 - - primary: DEAD - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - size: 20 - #Bandar Abbas Intl (51) - 2: - - primary: SEAD - secondary: air-to-ground - aircraft: - - F-4E Phantom II - size: 20 - - primary: TARCAP - secondary: air-to-air - aircraft: - - F-5E Tiger II - size: 16 - #Qeshm Island (12) - 13: - - primary: Air Assault - secondary: any - aircraft: - - Mi-24P Hind-F - size: 12 - #Abu Musa Island (8) - 1: - - primary: DEAD - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - size: 8 - #Kish Intl (46) - 24: - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK Fencer-D - size: 20 - - primary: Escort - secondary: any - aircraft: - - Mirage-F1EQ - size: 16 - #Shiraz Intl (122) - 19: - - primary: Transport - aircraft: - - IL-76MD - size: 5 - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - size: 12 - #Kerman - 18: - - primary: AEW&C - aircraft: - - A-50 - size: 1 - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14A Tomcat (Block 135-GR Late) - size: 10 diff --git a/resources/campaigns/operation_peace_spring.miz b/resources/campaigns/operation_peace_spring.miz deleted file mode 100644 index d44be71b4..000000000 Binary files a/resources/campaigns/operation_peace_spring.miz and /dev/null differ diff --git a/resources/campaigns/operation_peace_spring.yaml b/resources/campaigns/operation_peace_spring.yaml deleted file mode 100644 index ac50aa21c..000000000 --- a/resources/campaigns/operation_peace_spring.yaml +++ /dev/null @@ -1,160 +0,0 @@ ---- -name: Syria - Operation Peace Spring -theater: Syria -authors: Starfire -recommended_player_faction: Bluefor Modern -recommended_enemy_faction: Iraq 1991 -description: -

    This is a semi-fictional what-if scenario for Operation Peace Spring, - during which Turkish forces that crossed into Syria on an offensive against - Kurdish militias were emboldened by early successes to continue pushing - further southward. Attempts to broker a ceasefire have failed. Members of - Operation Inherent Resolve have gathered at Ramat David Airbase in Israel to - launch a counter-offensive.

    Note: The default faction - is set as Iraq 1991 in order to provide an opponent with a wider variety of - units. While Turkey 2005 would be the historical faction (and has preset - squadrons included), they only have two jets available (F-4 and F-16).

    -miz: operation_peace_spring.miz -performance: 2 -recommended_start_date: 2019-12-23 -version: "11.0" -squadrons: - Blue CV-1: - - primary: SEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 40 - - primary: BAI - secondary: air-to-ground - aircraft: - - S-3B Viking - size: 20 - - primary: AEW&C - aircraft: - - E-2D Advanced Hawkeye - size: 4 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 4 - Bombers from RAF Fairford: - - primary: DEAD - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - size: 8 - # Akrotiri - 44: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 8 - - primary: OCA/Runway - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 12 - - primary: TARCAP - secondary: air-to-air - aircraft: - - F-15C Eagle - size: 20 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 4 - # Ramat David - 30: - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 8 - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 28 - - primary: CAS - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 4 - # Damascus - 7: - - primary: Strike - secondary: air-to-ground - aircraft: - - F-4E Phantom II - - H-6J Badger - size: 16 - - primary: BAI - secondary: any - aircraft: - - AH-1W SuperCobra - - Su-25 Frogfoot - size: 16 - - primary: CAS - secondary: any - aircraft: - - OH-58D Kiowa Warrior - - Mi-24P Hind-F - size: 4 - # Tiyas - 39: - - primary: SEAD - secondary: air-to-ground - aircraft: - - F-16CM Fighting Falcon (Block 50) - - Su-24M Fencer-D - size: 16 - - primary: Escort - secondary: air-to-air - aircraft: - - F-4E Phantom II - - Mirage-F1EQ - size: 16 - # Abu Al Duhur - 1: - - primary: Fighter sweep - secondary: air-to-air - aircraft: - - F-4E Phantom II - - MiG-23ML Flogger-G - size: 8 - # Gaziantep - 11: - - primary: BARCAP - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - MiG-29A Fulcrum-A - size: 8 - # Incirlik - 16: - - primary: Strike - secondary: air-to-ground - aircraft: - - F-4E Phantom II - - Tu-22M3 Backfire-C - size: 16 - - primary: AEW&C - aircraft: - - E-3A - - A-50 - size: 1 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - - IL-78M - size: 1 - - primary: Escort - secondary: any - aircraft: - - F-4E Phantom II - - MiG-21bis Fishbed-N - size: 16 \ No newline at end of file diff --git a/resources/campaigns/operation_vectrons_claw.miz b/resources/campaigns/operation_vectrons_claw.miz deleted file mode 100644 index 79ca542c5..000000000 Binary files a/resources/campaigns/operation_vectrons_claw.miz and /dev/null differ diff --git a/resources/campaigns/operation_vectrons_claw.yaml b/resources/campaigns/operation_vectrons_claw.yaml deleted file mode 100644 index f0b59a79a..000000000 --- a/resources/campaigns/operation_vectrons_claw.yaml +++ /dev/null @@ -1,156 +0,0 @@ ---- -name: Caucasus - Operation Vectron's Claw -theater: Caucasus -authors: Starfire -recommended_player_faction: USA 2005 -recommended_enemy_faction: Russia 2010 -description: -

    Background - The United Nations Observer Mission in Georgia (UNOMIG) has been actively monitoring the ceasefire agreement between Georgia and its breakaway region of Abkhazia. Recent developments have escalated tensions in the area, leading to a precarious situation for UN observers and affiliated personnel. -

    Current Situation - UNOMIG observers, along with a contingent of international troops, have found themselves isolated due to the intervention of Russian forces supporting the separatist ambitions of Abkhazia. The UNOMIG headquarters located in Sukhumi has fallen into enemy hands. A smaller group based at the Zugdidi Sector Headquarters now faces the daunting task of navigating to safety with the aid of offshore naval air support. -

    Objective - The immediate goal is to orchestrate a strategic withdrawal of UN forces to the coastline, leveraging support from US naval aircraft positioned offshore. The critical mission objective is the rapid recapture of Sukhumi. This action is essential to enable the landing of friendly ground forces and the ferrying in of land-based sqwuadrons from Incirlik. -

    Operational Constraints - It is crucial to note that reinforcement of ground units will not be possible until Sukhumi is successfully recaptured. This recapture can either be performed using existing UN personnel and ground vehicles, or via heliborne assault troop insertion. -

    Assets & Support - Available assets include two Huey helicopters for close air support. Commanders may opt to initiate the operation with light vehicles, such as Humvees, employing breakthrough tactics to avoid direct confrontations with enemy forces. Alternatively, the use of heavier ground units is an option for commanders seeking a more conventional combat engagement. Upon the recapture of Sukhumi, additional squadrons from Incirlik, Turkey, will become operational. -

    Secondary Objective - Consider prioritising the capture of the Batumi airfield, located to the south, for its strategic value as a forward operating base. Commanders should be aware of the inherent risks, as the airfield is relatively small and lacks air defence systems, posing a significant threat to any stationed aircraft.

    -miz: operation_vectrons_claw.miz -performance: 1 -recommended_start_date: 2008-08-08 -version: "11.0" -control_points: - Squadrons from Incirlik: - ferry_only: true -squadrons: - Blue CV-1: - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - size: 16 - - primary: SEAD - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - size: 60 - - primary: CAS - secondary: air-to-ground - aircraft: - - S-3B Viking - size: 8 - - primary: AEW&C - aircraft: - - E-2C Hawkeye - size: 2 - - primary: Refueling - aircraft: - - S-3B Tanker - size: 2 - - primary: Air Assault - secondary: any - aircraft: - - UH-60L - - UH-60A - size: 2 - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack - size: 20 - Squadrons from Incirlik: - - primary: CAS - secondary: any - aircraft: - - AH-64D Apache Longbow - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 6 - - primary: DEAD - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - size: 16 - - primary: BAI - secondary: any - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 8 - - primary: Refueling - aircraft: - - KC-135 Stratotanker - size: 1 - Bombers from RAF Fairford: - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - size: 4 - Bombers from Base Aérea de Morón: - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 4 - #FARPs - UNOMIG Sector HQ: - - primary: Transport - secondary: any - aircraft: - - UH-1H Iroquois - size: 2 - Dzhugba: - - primary: CAS - secondary: any - aircraft: - - Mi-24P Hind-F - size: 4 - #Sukhumi-Babushara - 20: - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - size: 8 - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - size: 12 - #Sochi-Adler - 18: - - primary: Escort - secondary: air-to-air - aircraft: - - Su-27 Flanker-B - size: 8 - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - size: 20 - - primary: DEAD - secondary: air-to-ground - aircraft: - - Su-34 Fullback - size: 20 - #Maykop-Khanskaya - 16: - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-22M3 Backfire-C - size: 20 - #Anapa-Vityazevo - 12: - - primary: Strike - secondary: air-to-ground - aircraft: - - Tu-95MS Bear-H - size: 16 - Red CV: - - primary: BARCAP - secondary: any - aircraft: - - SU-33 Flanker-D - size: 16 \ No newline at end of file diff --git a/resources/campaigns/operation_velvet_thunder.miz b/resources/campaigns/operation_velvet_thunder.miz deleted file mode 100644 index fadf6f494..000000000 Binary files a/resources/campaigns/operation_velvet_thunder.miz and /dev/null differ diff --git a/resources/campaigns/operation_velvet_thunder.yaml b/resources/campaigns/operation_velvet_thunder.yaml deleted file mode 100644 index 80119d9b3..000000000 --- a/resources/campaigns/operation_velvet_thunder.yaml +++ /dev/null @@ -1,99 +0,0 @@ ---- -name: Marianas - Operation Velvet Thunder -theater: MarianaIslands -authors: Starfire -recommended_player_faction: USA 1970 -recommended_enemy_faction: NVA 1970 -description: -

    Operation Velvet Thunder is a high-intensity training exercise designed to - prepare fresh troops for the challenges they will face in Vietnam. The dense - jungle and rugged terrain of the Mariana Islands will provide a realistic - backdrop, allowing our forces to hone essential skills in jungle warfare, - unconventional tactics, and counterinsurgency operations. There are multiple - checkpoints scattered across the area of operations that will have to be - captured by Air Assault. Due to the limited size and availability of LZs, it - is vital to pay close attention to where you designate troop drop off zones. -

    Note: This campaign is intended to be played with the - A-4 Skyhawk and OV-10a aircraft mods active. The C-101CC has also been included - as a stand-in for the Cessna A-37 Dragonfly in order to provide a CAS platform - of roughly equivalent combat capability. This campaign will be updated to use - Heatblur's F-4 Phantom II once it is in early access.

    -miz: operation_velvet_thunder.miz -performance: 1 -recommended_start_date: 1970-11-29 -version: "11.0" -settings: - a4_skyhawk: true - f4bc_phantom: true - ov10a_bronco: true -squadrons: - #Andersen AFB - 6: - - primary: Escort - secondary: any - aircraft: - - F-5E Tiger II - size: 8 - - primary: BAI - secondary: any - aircraft: - - C-101CC Aviojet - size: 8 - - primary: CAS - secondary: any - aircraft: - - OV-10A Bronco - size: 8 - - primary: SEAD - secondary: any - aircraft: - - F-4C Phantom II - - F-4E Phantom II - size: 8 - - primary: Strike - secondary: any - aircraft: - - B-52H Stratofortress - size: 4 - - primary: Air Assault - secondary: any - aircraft: - - UH-1H Iroquois - size: 4 - - primary: Transport - secondary: any - aircraft: - - CH-47D - size: 4 - #Blue CV - Blue-CV: - - primary: DEAD - secondary: any - aircraft: - - A-4E Skyhawk - size: 16 - - primary: AEW&C - aircraft: - - E-2C Hawkeye - size: 2 - #Rota Intl - 1: - - primary: TARCAP - secondary: any - aircraft: - - MiG-19P Farmer-B - size: 8 - #Tinian Intl - 3: - - primary: Air Assault - secondary: any - aircraft: - - Mi-8MTV2 Hip - size: 4 - #Saipan Intl - 2: - - primary: BAI - secondary: any - aircraft: - - MiG-21bis Fishbed-N - size: 8 \ No newline at end of file diff --git a/resources/campaigns/pacific_repartee.miz b/resources/campaigns/pacific_repartee.miz deleted file mode 100644 index 58033b2f7..000000000 Binary files a/resources/campaigns/pacific_repartee.miz and /dev/null differ diff --git a/resources/campaigns/pacific_repartee.yaml b/resources/campaigns/pacific_repartee.yaml deleted file mode 100644 index bce8776f6..000000000 --- a/resources/campaigns/pacific_repartee.yaml +++ /dev/null @@ -1,149 +0,0 @@ ---- -name: Marianas - Pacific Repartee -theater: MarianaIslands -authors: Fuzzle -description:

    A naval campaign where a US carrier group must retake Guam, Saipan and the Marianas Islands from the Chinese. This is a purely naval campaign, meaning you will need to use the Air Assault mission type with transports to take FOBs/airbases. Ensure you soften them up enough first!

    Backstory: After an escalation in the South China Sea, the PLAN has taken the US by surprise and invaded Guam, setting up supporting positions throughout the Marianas island chain. With the rest of the US Navy engaged near Japan, a carrier task group must push through China's forces, assist a small Marine contingent holding out on Farallon de Pajaros and liberate Guam.

    -version: "11.0" -recommended_player_faction: US Navy 2005 -recommended_enemy_faction: China 2010 -miz: pacific_repartee.miz -performance: 1 -recommended_start_date: 2006-02-17 -recommended_player_money: 1000 -recommended_enemy_money: 1500 -recommended_player_income_multiplier: 1.3 -recommended_enemy_income_multiplier: 0.6 -squadrons: - #BLUFOR CVN - Naval-1: - - primary: BARCAP - secondary: any - aircraft: - - VF-143 - size: 14 - - primary: SEAD - secondary: air-to-ground - aircraft: - - VMFA-251 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - # BLUFOR LHA - Naval-2: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-169 (AH-1W) - size: 6 - # OPFOR CVN 1 - Naval-3: - - primary: BARCAP - secondary: any - aircraft: - - J-15 Flanker X-2 - - primary: Strike - secondary: any - aircraft: - - J-15 Flanker X-2 - # OPFOR CVN 2 - Naval-4: - - primary: BARCAP - secondary: any - aircraft: - - J-15 Flanker X-2 - - primary: Strike - secondary: any - aircraft: - - J-15 Flanker X-2 - # OPFOR CVN 3 - Naval-28: - - primary: BARCAP - secondary: any - aircraft: - - J-15 Flanker X-2 - - primary: TARCAP - secondary: any - aircraft: - - J-15 Flanker X-2 - # OPFOR LHA - OPLHA: - - primary: Strike - secondary: any - aircraft: - - Mi-24P Hind-F - # Saipan Intl - 2: - - primary: Transport - aircraft: - - IL-76MD - size: 2 - - primary: BARCAP - secondary: any - aircraft: - - J-7B - size: 8 - - primary: BARCAP - secondary: any - aircraft: - - FC-1 Fierce Dragon - size: 9 - # Tinian Intl - 3: - - primary: Refueling - aircraft: - - IL-78M - size: 2 - # Andersen AFB - 6: - - primary: TARCAP - secondary: any - aircraft: - - J-11A Flanker-L - - primary: BARCAP - secondary: air-to-ground - aircraft: - - FC-1 Fierce Dragon - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - H-6J Badger - - primary: Transport - aircraft: - - IL-76MD - size: 2 - # Antonio B. Won Pat Intl - 4: - - primary: TARCAP - secondary: any - aircraft: - - J-7B - size: 10 - - primary: BARCAP - secondary: air-to-ground - aircraft: - - FC-1 Fierce Dragon - size: 12 diff --git a/resources/campaigns/scenic_inland.miz b/resources/campaigns/scenic_inland.miz deleted file mode 100644 index eb161b6ad..000000000 Binary files a/resources/campaigns/scenic_inland.miz and /dev/null differ diff --git a/resources/campaigns/scenic_inland.yaml b/resources/campaigns/scenic_inland.yaml deleted file mode 100644 index 44058bd97..000000000 --- a/resources/campaigns/scenic_inland.yaml +++ /dev/null @@ -1,286 +0,0 @@ ---- -name: Persian Gulf - Scenic Route 2 - Dust To Dust -theater: Persian Gulf -authors: Fuzzle -description:

    A continuation of Scenic Route. A NATO coalition pushes inland along a protracted axis of advance. Built with helicopters/FOB-based gameplay in mind.

    Backstory: With Iran's coastal defences pacified and their forces pushed inland, a beleaguered US Navy is reinforced by a NATO coalition task force. The going will not be easy however; Iran has assembled the full might of its armoured and mechanized divisions alongside rotary support to defend their heartland. The conflict intensifies.

    -version: "11.0" -advanced_iads: true -recommended_player_faction: NATO OIF -recommended_enemy_faction: Iran 2015 -miz: scenic_inland.miz -performance: 2 -recommended_start_date: 2005-06-29 -recommended_player_money: 1200 -recommended_enemy_money: 1400 -recommended_player_income_multiplier: 1.1 -recommended_enemy_income_multiplier: 0.7 -squadrons: - # Bandar Abbas Intl - 2: - - primary: TARCAP - secondary: air-to-air - aircraft: - - Escadron de chasse 1/30 - #French Mirage2000C - - primary: SEAD - secondary: any - aircraft: - - 77th FS - #USAF F-16C - - primary: Strike - secondary: air-to-ground - aircraft: - - No. 12 Squadron - #RAF Tornado GR.4 - - primary: Transport - secondary: air-to-ground - aircraft: - - 101st Combat Aviation Brigade - #US Army UH-60 - size: 6 - # Havadarya - 9: - - primary: BARCAP - secondary: any - aircraft: - - 493rd FS - #USAF F-15C - size: 12 - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - size: 10 - #USAF A-10CI - #BLUFOR CVN - BLUFOR CVN: - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-143 - - primary: DEAD - secondary: any - aircraft: - - VMFA-251 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - # BLUFOR LHA - BLUFOR LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - # BLUFOR Start FOB - FOB Anguran: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - #French Gazelle - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - Wolfpack, 1-82 ARB - #US Army Apache AH-64D - size: 2 - # OPFOR L1F1 - FOB Tang-e Dalan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L1F2 - FOB Fars Border: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L1F2 split - FOB Bikuyeh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 - # Lar - 11: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-21bis Fishbed-N - size: 5 - # OPFOR L2F1 - FOB Mansurabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L2F2 - FOB Jahrom: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L2F3 - FOB Tower: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L2F3 split - FOB Nouderan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 - # Shiraz Intl - 19: - - primary: AEW&C - aircraft: - - A-50 - size: 2 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - - primary: BARCAP - secondary: any - aircraft: - - F-4E Phantom II - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-22M4 Fitter-K - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 4 - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - # OPFOR L3F1 - FOB Kherameh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F2 - FOB Tashk: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F3 - FOB Chahak: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F4 - FOB Plainhold: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F4 split - FOB Robat: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F5 - FOB Plainguard: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F6 - FOB Hasanabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F6 split - FOB Najafabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 - # OPFOR L3F7 - FOB Kabutarkhan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # OPFOR L3F8 - FOB Sa'di: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # Kerman - 18: - - primary: AEW&C - aircraft: - - A-50 - size: 2 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - - primary: Transport - aircraft: - - IL-78MD - size: 2 - - primary: BARCAP - secondary: any - aircraft: - - F-14A Tomcat (Block 135-GR Late) - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - size: 6 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK Fencer-D - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 \ No newline at end of file diff --git a/resources/campaigns/scenic_merge.miz b/resources/campaigns/scenic_merge.miz deleted file mode 100644 index 708ce7328..000000000 Binary files a/resources/campaigns/scenic_merge.miz and /dev/null differ diff --git a/resources/campaigns/scenic_merge.yaml b/resources/campaigns/scenic_merge.yaml deleted file mode 100644 index cdfff0615..000000000 --- a/resources/campaigns/scenic_merge.yaml +++ /dev/null @@ -1,387 +0,0 @@ ---- -name: Persian Gulf - Scenic Route Merged -theater: Persian Gulf -authors: Fuzzle, merged by tmz42 -description:

    A merge of the two Scenic Route campaigns.

    Backstory: Iran has declared war on all US forces in the Gulf resulting in all local allies withdrawing their support for American troops. A carrier group, aided by USAF units stationed on the south bank must pacify Iran's coastal defences and push inland. Iran has assembled the full might of its air and ground divisions to defend their heartland.

    -version: "11.0" -advanced_iads: true -recommended_player_faction: USA 2005 -recommended_enemy_faction: Iran 2015 -miz: scenic_merge.miz -performance: 3 -recommended_start_date: 2005-06-29 -recommended_player_money: 2000 -recommended_enemy_money: 1000 -recommended_player_income_multiplier: 1.5 -recommended_enemy_income_multiplier: 0.7 -squadrons: - #BLUFOR CVN - Naval-3: - # Pukin' Dogs F-14 - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-143 - size: 14 - # Golden Dragons F/A-18 - - primary: SEAD - secondary: any - aircraft: - - VFA-192 - size: 12 - # Thunderbolts F/A-18C - - primary: DEAD - secondary: any - aircraft: - - VMFA-251 - size: 12 - # Hawkeye - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - # S-3 Tankers - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - # BLUFOR LHA - Naval-4: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 12 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 8 - # Al-Dhafra AFB - 4: - #USAF F-16C Gamblers - - primary: SEAD - secondary: any - aircraft: - - 77th FS - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - size: 6 - - primary: Refueling - size: 2 - aircraft: - - 18th Air Refueling Squadron - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - - primary: AEW&C - aircraft: - - E-3 - size: 2 - - primary: BARCAP - secondary: any - aircraft: - - 493rd FS - #USAF F-15C - # Al-Minhab AFB - 12: - - primary: Transport - secondary: air-to-ground - aircraft: - - 101st Combat Aviation Brigade - #US Army UH-60 - size: 6 - - primary: SEAD - secondary: any - aircraft: - - 480th FS - #USAF F-16C - - primary: Strike - secondary: air-to-ground - aircraft: - - F-15E Strike Eagle (Suite 4+) - # Strike Eagle (Chiefs?) - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - #USAF A-10CII - - primary: Transport - aircraft: - - C-130 - size: 8 - # Kish Intl - 24: - - primary: AEW&C - aircraft: - - A-50 - size: 1 - - primary: BARCAP - secondary: any - aircraft: - - F-14A Tomcat (Block 135-GR Late) - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK Fencer-D - size: 12 - # Havadarya - 9: - - primary: BARCAP - secondary: any - aircraft: - - F-4E Phantom II - size: 6 - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - size: 6 - # Bandar Abbas Intl - 2: - - primary: TARCAP - secondary: any - aircraft: - - F-5E Tiger II - size: 6 - - primary: BARCAP - secondary: air-to-ground - aircraft: - - MiG-29A Fulcrum-A - size: 6 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK - size: 6 - # OPFOR First FOB - FOB Seerik: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 2 - # OPFOR Second FOB - FOB Kohnehshahr: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-F - size: 2 - # OPFOR Third FOB - FOB Khvosh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 2 - # OPFOR Last FOB - FOB Charak: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 2 - # BLUFOR Start FOB - FOB Anguran: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-F - size: 2 - # OPFOR L1F1 - FOB Tang-e Dalan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L1F2 - FOB Fars Border: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L1F2 split - FOB Bikuyeh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 2 - # Lar - 11: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-21bis Fishbed-N - size: 4 - # OPFOR L2F1 - FOB Mansurabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L2F2 - FOB Jahrom: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L2F3 - FOB Tower: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L2F3 split - FOB Nouderan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 2 - # Shiraz Intl - 19: - - primary: AEW&C - aircraft: - - A-50 - size: 2 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-22M4 Fitter-K - size: 6 - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 4 - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - size: 6 - # OPFOR L3F1 - FOB Kherameh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F2 - FOB Tashk: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F3 - FOB Chahak: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F4 - FOB Plainhold: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F4 split - FOB Robat: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F5 - FOB Plainguard: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F6 - FOB Hasanabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F6 split - FOB Najafabad: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 2 - # OPFOR L3F7 - FOB Kabutarkhan: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # OPFOR L3F8 - FOB Sa'di: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 - # Kerman - 18: - - primary: AEW&C - aircraft: - - A-50 - size: 2 - - primary: Refueling - aircraft: - - IL-78M - size: 2 - - primary: Transport - aircraft: - - IL-78MD - size: 2 - - primary: BARCAP - secondary: any - aircraft: - - F-14A Tomcat (Block 135-GR Late) - size: 12 - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-29A Fulcrum-A - size: 12 - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK Fencer-D - size: 6 - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 2 \ No newline at end of file diff --git a/resources/campaigns/scenic_route.miz b/resources/campaigns/scenic_route.miz deleted file mode 100644 index 6b3df3b3f..000000000 Binary files a/resources/campaigns/scenic_route.miz and /dev/null differ diff --git a/resources/campaigns/scenic_route.yaml b/resources/campaigns/scenic_route.yaml deleted file mode 100644 index 0ce140413..000000000 --- a/resources/campaigns/scenic_route.yaml +++ /dev/null @@ -1,154 +0,0 @@ ---- -name: Persian Gulf - Scenic Route -theater: Persian Gulf -authors: Fuzzle -description:

    A lightweight naval campaign involving a US Navy carrier group pushing across the coast of Iran. This is a purely naval campaign, meaning you will need to use the Air Assault mission type with transports to take the first FOB. Ensure you soften it up enough first!

    Backstory: Iran has declared war on all US forces in the Gulf resulting in all local allies withdrawing their support for American troops. A lone carrier group must pacify the southern coast of Iran and hold out until backup can arrive lest the US and her interests be ejected from the region permanently.

    -version: "11.0" -advanced_iads: true -recommended_player_faction: US Navy 2005 -recommended_enemy_faction: Iran 2015 -miz: scenic_route.miz -performance: 1 -recommended_start_date: 2005-04-26 -recommended_player_money: 1000 -recommended_enemy_money: 1300 -recommended_player_income_multiplier: 1.2 -recommended_enemy_income_multiplier: 0.7 -squadrons: - #BLUFOR CVN - Naval-1: - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-143 - size: 14 - - primary: SEAD - secondary: air-to-ground - aircraft: - - VFA-113 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - # BLUFOR LHA - Naval-2: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-169 (AH-1W) - size: 6 - # OPFOR Start FOB - FOB Bandar-e-Jask: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-F - size: 6 - # OPFOR CVN - Naval-3: - - primary: BARCAP - secondary: any - - primary: Strike - secondary: any - - primary: BAI - secondary: any - - primary: Refueling - # Kish Intl - 24: - - primary: AEW&C - aircraft: - - A-50 - size: 1 - - primary: BARCAP - secondary: any - aircraft: - - F-14A Tomcat (Block 135-GR Late) - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK Fencer-D - - primary: BARCAP - secondary: any - aircraft: - - F-4E Phantom II - # Havadarya - 9: - - primary: BARCAP - secondary: any - aircraft: - - F-4E Phantom II - size: 10 - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - size: 12 - # Bandar Abbas Intl - 2: - - primary: TARCAP - secondary: any - aircraft: - - F-5E Tiger II - - primary: BARCAP - secondary: air-to-ground - aircraft: - - MiG-29A Fulcrum-A - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24MK - - primary: BARCAP - secondary: air-to-ground - aircraft: - - F-4E Phantom II - # OPFOR First FOB - FOB Seerik: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - size: 6 - # OPFOR Second FOB - FOB Kohnehshahr: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-F - size: 6 - # OPFOR Third FOB - FOB Khvosh: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 - # OPFOR Last FOB - FOB Charak: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - size: 6 \ No newline at end of file diff --git a/resources/campaigns/syria_full_map.miz b/resources/campaigns/syria_full_map.miz deleted file mode 100644 index 2aab205a2..000000000 Binary files a/resources/campaigns/syria_full_map.miz and /dev/null differ diff --git a/resources/campaigns/syria_full_map.yaml b/resources/campaigns/syria_full_map.yaml deleted file mode 100644 index 5f02b5743..000000000 --- a/resources/campaigns/syria_full_map.yaml +++ /dev/null @@ -1,297 +0,0 @@ ---- -name: Syria - Full Map -theater: Syria -authors: Plob -description:

    A long campaign across the syria map, strap in.

    -recommended_player_faction: Bluefor Modern -recommended_enemy_faction: Syria 2012'ish -recommended_start_date: 2012-06-05 -miz: syria_full_map.miz -performance: 3 -version: "10.5" -squadrons: - # Incirlik - 16: - - primary: Refueling - aircraft: - - KC-135 Stratotanker MPRS - - primary: Refueling - aircraft: - - KC-135 Stratotanker - - primary: AEW&C - aircraft: - - E-3A - - primary: Transport - secondary: any - aircraft: - - C-130 - - primary: Strike - secondary: any - aircraft: - - F-16CM Fighting Falcon (Block 50) - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 3) - - primary: BARCAP - secondary: any - aircraft: - - JF-17 Thunder - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - - primary: BAI - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - - primary: Strike - secondary: any - aircraft: - - AJS-37 Viggen - - primary: Strike - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - - primary: Strike - secondary: any - aircraft: - - Mirage 2000C - # Gaziantep - 11: - - primary: CAS - secondary: air-to-ground - aircraft: - - UH-1H Iroquois - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - primary: CAS - secondary: air-to-ground - aircraft: - - AH-64D Apache Longbow - # Hatay - 15: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - # Tabqa - 37: - - primary: Strike - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BARCAP - aircraft: - - MiG-23MLD Flogger-K - # Abu al-Duhur - 1: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: Fighter sweep - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - - primary: Transport - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - # Bassel Al-Assad - 21: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - - primary: Intercept - secondary: air-to-air - aircraft: - - MiG-25PD Foxbat-E - - primary: Strike - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: AEW&C - aircraft: - - A-50 - # Al Qusayr - 3: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - # Palmyra - 28: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-30 Flanker-C - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - # Rayak - 32: - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-30 Flanker-C - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-23MLD Flogger-K - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - primary: OCA/Runway - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - # Damascus - 7: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-25PD Foxbat-E - - primary: Strike - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: BAI - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-30 Flanker-C - - primary: Transport - aircraft: - - IL-78M - - primary: Transport - secondary: air-to-ground - aircraft: - - Mi-8MTV2 Hip - # King Hussein Air College - 19: - - primary: BAI - secondary: air-to-air - aircraft: - - L-39ZA Albatros - - primary: BAI - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: BARCAP - secondary: air-to-air - aircraft: - - Su-30 Flanker-C - # Ramat David - 30: - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - - primary: Intercept - secondary: air-to-air - aircraft: - - MiG-25PD Foxbat-E - - primary: Strike - secondary: air-to-air - aircraft: - - Su-34 Fullback - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - - primary: BARCAP - secondary: air-to-air - aircraft: - - MiG-29S Fulcrum-C - - primary: AEW&C - aircraft: - - A-50 - - Blue CV: - - primary: BARCAP - secondary: air-to-air - aircraft: - - F-14B Tomcat - - primary: BARCAP - secondary: any - aircraft: - - F-14B Tomcat - - primary: Strike - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: BAI - secondary: any - aircraft: - - F/A-18C Hornet (Lot 20) - - primary: Refueling - aircraft: - - S-3B Tanker - - primary: AEW&C - aircraft: - - E-2C Hawkeye - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - AV-8B Harrier II Night Attack diff --git a/resources/campaigns/tripoint_hostility.miz b/resources/campaigns/tripoint_hostility.miz deleted file mode 100644 index 80321de85..000000000 Binary files a/resources/campaigns/tripoint_hostility.miz and /dev/null differ diff --git a/resources/campaigns/tripoint_hostility.yaml b/resources/campaigns/tripoint_hostility.yaml deleted file mode 100644 index 9b6c71f35..000000000 --- a/resources/campaigns/tripoint_hostility.yaml +++ /dev/null @@ -1,213 +0,0 @@ ---- -name: Syria - Tripoint Hostility -theater: Syria -authors: Fuzzle -description:

    A joint US Army/Air Force force must push Iraqi aggressors back through Jordan and Syria to the border, then pacify Iraq's nearby airbases. This campaign showcases the southeastern expansion to the Syria terrain, and incentivizes heavy usage of rotary from FARPs.

    Backstory: In an alternate 2006, Iraq has seen a coup place a hardline national fundamentalist movement in power, who have ejected US forces from the country under threat from newfound Iranian allies. With their confidence unchecked, Iraq has invaded their Jordanian and Syrian neighbours to the west, pushing nearly to the Israeli border. To keep the region from falling to chaos, the US has redeployed a task force from Europe to defend Jordan and bring down Iraq's west-facing air power.

    -recommended_player_faction: USA 2005 -recommended_enemy_faction: Iraq 1991 -miz: tripoint_hostility.miz -performance: 2 -version: "11.0" -recommended_start_date: 2006-08-03 -recommended_player_money: 900 -recommended_enemy_money: 1200 -recommended_player_income_multiplier: 1.0 -recommended_enemy_income_multiplier: 0.6 -squadrons: - #BLUFOR CVN - Naval-1: - - primary: BARCAP - secondary: any - aircraft: - - VF-143 - size: 14 - - primary: SEAD - secondary: air-to-ground - aircraft: - - VFA-192 - - primary: AEW&C - aircraft: - - VAW-125 - size: 2 - - primary: Refueling - aircraft: - - VS-35 (Tanker) - size: 4 - - primary: Anti-ship - secondary: air-to-ground - aircraft: - - VS-35 - size: 8 - - primary: Transport - aircraft: - - HSM-40 - size: 2 - # BLUFOR LHA - Naval-2: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - size: 10 - - primary: Transport - secondary: air-to-ground - aircraft: - - HMLA-169 (UH-1H) - size: 4 - - primary: CAS - secondary: air-to-ground - aircraft: - - HMLA-169 (AH-1W) - size: 6 - # Incirlik - 16: - - primary: Strike - secondary: air-to-ground - aircraft: - - B-1B Lancer - - primary: AEW&C - aircraft: - - 960th AAC Squadron - #USAF E-3A - size: 2 - - primary: Strike - secondary: air-to-ground - aircraft: - - F-15E Strike Eagle (Suite 4+) - size: 12 - - primary: SEAD - secondary: any - aircraft: - - 77th FS - #USAF F-16C - size: 12 - # King Hussein Air College, BLUFOR start - 19: - - primary: BAI - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - #USAF A-10CII - size: 8 - - primary: BARCAP - secondary: air-to-air - aircraft: - - 493rd FS - #USAF F-15C - - primary: SEAD - secondary: any - aircraft: - - 23rd FS - #USAF F-16C - - primary: Transport - secondary: air-to-ground - aircraft: - - 101st Combat Aviation Brigade - #US Army UH-60 - size: 4 - # FOB Tha'lah, BLUFOR 1st FOB north - FOB Tha'lah: - - primary: CAS - size: 6 - secondary: air-to-ground - aircraft: - - A Company, 1-227th ARB - #US Army AH-64D - # FOB Stalwart, first BLUFOR FOB south - FOB Stalwart: - - primary: CAS - secondary: air-to-ground - aircraft: - - C Company, 2-159th ARB - size: 6 - #US Army AH-64D - # FOB Qalea, first OPFOR FOB south - FOB Qalea: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - # H4 Airbase, 1st OPFOR airfield south - size: 6 - 12: - - primary: BARCAP - secondary: any - aircraft: - - MiG-21bis Fishbed-N - # FOB Eadla, 2nd OPFOR FOB south - FOB Eadla: - - primary: CAS - secondary: air-to-ground - size: 6 - aircraft: - - Mi-24P Hind-F - # Ruwayshid, 2nd OPFOR airfield south - 57: - - primary: BAI - secondary: air-to-ground - aircraft: - - Su-22M4 Fitter-K - # H3 Southwest, 3rd OPFOR airfield south - 55: - - primary: BARCAP - secondary: any - aircraft: - - MiG-29A Fulcrum-A - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - # H3 Airbase, 4th-last OPFOR airfield south - 53: - - primary: TARCAP - secondary: air-to-air - aircraft: - - MiG-25PD Foxbat-E - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - # Khalkhalah, 1st OPFOR airfield north - 18: - - primary: BARCAP - secondary: any - aircraft: - - MiG-19P Farmer-B - # FOB Dhirae, 1st OPFOR FOB north - FOB Dhirae: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - size: 6 - # FOB Kataf, 2nd OPFOR FOB north - FOB Kataf: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # At Tanf, 3rd OPFOR heliport north - 63: - - primary: CAS - secondary: air-to-ground - aircraft: - - SA 342M Gazelle - size: 2 - # FOB Qalb, 4th OPFOR FOB north - FOB Qalb: - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - size: 6 - # H3 Northwest, 2nd OPFOR airfield north - 54: - - primary: BARCAP - secondary: any - aircraft: - - MiG-21bis Fishbed-N - - primary: CAS - secondary: air-to-ground - aircraft: - - Su-22M4 Fitter-K \ No newline at end of file diff --git a/resources/campaigns/up_the_coast.miz b/resources/campaigns/up_the_coast.miz deleted file mode 100644 index d95fb83d5..000000000 Binary files a/resources/campaigns/up_the_coast.miz and /dev/null differ diff --git a/resources/campaigns/up_the_coast.yaml b/resources/campaigns/up_the_coast.yaml deleted file mode 100644 index 58ffc8741..000000000 --- a/resources/campaigns/up_the_coast.yaml +++ /dev/null @@ -1,185 +0,0 @@ ---- -name: Caucasus - Up The Coast -theater: Caucasus -authors: HolyOrangeJuice, We Run Liberation -recommended_player_faction: Bluefor Modern -recommended_enemy_faction: Russia 1975 -description: -

    In this mission, it is just as important to kill the economy generating - buildings, as it is to kill the enemy ground units. The enemy will be able to - spend a lot of money replacing units if you do not target the - buildings.

    Each airbase has one or more factories. Each airbase has only - three ammo targets.

    -miz: up_the_coast.miz -performance: 1 -version: "10.2" -recommended_start_date: 2005-12-12 -recommended_player_money: 2000 -recommended_enemy_money: 2000 -recommended_player_income_multiplier: 1.0 -recommended_enemy_income_multiplier: 1.0 -squadrons: - Blue CV-1: - - primary: BARCAP - secondary: any - aircraft: - - VF-142 - #F14B - - primary: SEAD - secondary: any - aircraft: - - VFA-192 - #Hornet Navy - - primary: AEW&C - aircraft: - - VAW-125 - #E2C - - primary: Refueling - aircraft: - - S-3B Tanker - Blue LHA: - - primary: BAI - secondary: air-to-ground - aircraft: - - VMA-223 - #AV8B - - primary: CAS - secondary: air-to-ground - aircraft: - - AH-64D Apache Longbow - #FARPs - ZUGDIDI: - - primary: BAI - secondary: air-to-ground - aircraft: - - AH-64D Apache Longbow - - primary: BAI - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - primary: BAI - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - - primary: Strike - secondary: air-to-ground - #Sukhumi-Babushara - 20: - - primary: BARCAP - secondary: any - aircraft: - - MiG-21bis Fishbed-N - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24V Hind-E - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-24P Hind-F - - primary: CAS - secondary: air-to-ground - aircraft: - - Ka-50 Hokum - - primary: CAS - secondary: air-to-ground - aircraft: - - Mi-28N Havoc - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-25 Frogfoot - # Gudauta - 21: - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-17M4 Fitter-K - - primary: Strike - secondary: air-to-ground - aircraft: - - Su-24M Fencer-D - #Anapa-Vityazevo - 12: - - primary: BARCAP - secondary: any - aircraft: - - MiG-29A Fulcrum-A - - primary: AEW&C - aircraft: - - A-50 - # Senaki-Kholki - 23: - - primary: BARCAP - secondary: air-to-air - aircraft: - - 58th FS - #F15c - - primary: BARCAP - secondary: air-to-air - aircraft: - - VF-143 - #F14B - - primary: BARCAP - secondary: air-to-ground - aircraft: - - F-5E Tiger II - - primary: BARCAP - secondary: air-to-ground - aircraft: - - Mirage 2000C - - primary: BARCAP - secondary: air-to-ground - aircraft: - - JF-17 Thunder - - primary: Strike - secondary: any - aircraft: - - 23rd FS - #Viper USAF - - primary: BARCAP - secondary: air-to-ground - aircraft: - - VMA-214 - #AV8B - - primary: Strike - secondary: air-to-ground - aircraft: - - AJS-37 Viggen - - primary: Strike - secondary: air-to-ground - aircraft: - - 335th FS - #F15e - - primary: SEAD - secondary: air-to-ground - aircraft: - - VMFA-251 - #Hornet - Marines - - primary: SEAD - secondary: air-to-ground - aircraft: - - Su-25T Frogfoot - - primary: CAS - secondary: air-to-ground - aircraft: - - 74th TFS - #A10c s3 - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10C Thunderbolt II (Suite 7) - - primary: CAS - secondary: air-to-ground - aircraft: - - A-10A Thunderbolt II - - primary: Strike - secondary: air-to-ground - aircraft: - - B-52H Stratofortress - - primary: AEW&C - aircraft: - - E-3A - - primary: Refueling - aircraft: - - KC-135 Stratotanker MPRS diff --git a/resources/cau_groundobjects.p b/resources/cau_groundobjects.p deleted file mode 100644 index c7f616e67..000000000 Binary files a/resources/cau_groundobjects.p and /dev/null differ diff --git a/resources/caucasus.p b/resources/caucasus.p deleted file mode 100644 index a6cb642ee..000000000 Binary files a/resources/caucasus.p and /dev/null differ diff --git a/resources/caumap.gif b/resources/caumap.gif deleted file mode 100644 index 53a4a774d..000000000 Binary files a/resources/caumap.gif and /dev/null differ diff --git a/resources/customized_payloads/A-10A.lua b/resources/customized_payloads/A-10A.lua deleted file mode 100644 index 7f76e1b0b..000000000 --- a/resources/customized_payloads/A-10A.lua +++ /dev/null @@ -1,154 +0,0 @@ -local unitPayloads = { - ["name"] = "A-10A", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "Fuel_Tank_FT600", - ["num"] = 6, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 10, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [9] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9P5", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - }, - ["tasks"] = { - }, - }, - }, - ["unitType"] = "A-10A", -} -return unitPayloads diff --git a/resources/customized_payloads/A-10C.lua b/resources/customized_payloads/A-10C.lua deleted file mode 100644 index a74095bcc..000000000 --- a/resources/customized_payloads/A-10C.lua +++ /dev/null @@ -1,174 +0,0 @@ -local unitPayloads = { - ["name"] = "A-10C", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "Fuel_Tank_FT600", - ["num"] = 6, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 3, - }, - [10] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "A-10C", -} -return unitPayloads diff --git a/resources/customized_payloads/A-10C_2.lua b/resources/customized_payloads/A-10C_2.lua deleted file mode 100644 index bae0f0488..000000000 --- a/resources/customized_payloads/A-10C_2.lua +++ /dev/null @@ -1,219 +0,0 @@ -local unitPayloads = { - ["name"] = "A-10C II", - ["payloads"] = { - [1] = { - ["name"] = "New Payload", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-131x3 - 7 AGR-20A}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{LAU-131x3 - 7 AGR-20 M282}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{LAU-131x3 - 7 AGR-20A}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{LAU-131x3 - 7 AGR-20 M282}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20 M282}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20 M282}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20A}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20 M282}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "ALQ_184", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{LAU-131 - 7 AGR-20 M282}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 5, - }, - [9] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 8, - }, - [10] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "A-10C_2", -} -return unitPayloads diff --git a/resources/customized_payloads/A-20G.lua b/resources/customized_payloads/A-20G.lua deleted file mode 100644 index f627bf4fb..000000000 --- a/resources/customized_payloads/A-20G.lua +++ /dev/null @@ -1,72 +0,0 @@ -local unitPayloads = { - ["name"] = "A-20G", - ["payloads"] = { - [1] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4xAN-M64_on_InvCountedAttachmentPoints}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 30, - [3] = 17, - }, - ["unitType"] = "A-20G", -} -return unitPayloads diff --git a/resources/customized_payloads/A-4E-C.lua b/resources/customized_payloads/A-4E-C.lua deleted file mode 100644 index 8116cd4f9..000000000 --- a/resources/customized_payloads/A-4E-C.lua +++ /dev/null @@ -1,384 +0,0 @@ -local unitPayloads = { - ["name"] = "A-4E-C", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "Aerobatics", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [7] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [9] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AIM-9P5-ON-ADAPTER}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [10] = { - ["displayName"] = "Liberation SEAD Escort", - ["name"] = "Liberation SEAD Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [11] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [12] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [13] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "A-4E-C", -} -return unitPayloads diff --git a/resources/customized_payloads/AH-1W.lua b/resources/customized_payloads/AH-1W.lua deleted file mode 100644 index a8fb30b3b..000000000 --- a/resources/customized_payloads/AH-1W.lua +++ /dev/null @@ -1,69 +0,0 @@ -local unitPayloads = { - ["name"] = "AH-1W", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "M260_HYDRA", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "M260_HYDRA", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "M260_HYDRA", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "M260_HYDRA", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - }, - }, - }, - ["unitType"] = "AH-1W", -} -return unitPayloads diff --git a/resources/customized_payloads/AH-64A.lua b/resources/customized_payloads/AH-64A.lua deleted file mode 100644 index 1bce3138d..000000000 --- a/resources/customized_payloads/AH-64A.lua +++ /dev/null @@ -1,142 +0,0 @@ -local unitPayloads = { - ["name"] = "AH-64A", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - }, - ["unitType"] = "AH-64A", -} -return unitPayloads diff --git a/resources/customized_payloads/AH-64D.lua b/resources/customized_payloads/AH-64D.lua deleted file mode 100644 index cac514d3b..000000000 --- a/resources/customized_payloads/AH-64D.lua +++ /dev/null @@ -1,142 +0,0 @@ -local unitPayloads = { - ["name"] = "AH-64D", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 31, - [3] = 32, - [4] = 30, - }, - }, - }, - ["unitType"] = "AH-64D", -} -return unitPayloads diff --git a/resources/customized_payloads/AH-64D_BLK_II.lua b/resources/customized_payloads/AH-64D_BLK_II.lua deleted file mode 100644 index 2850bd4f8..000000000 --- a/resources/customized_payloads/AH-64D_BLK_II.lua +++ /dev/null @@ -1,150 +0,0 @@ -local unitPayloads = { - ["name"] = "AH-64D_BLK_II", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{AN_APG_78}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{M261_M229}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{M261_M229}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{AN_APG_78}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{AN_APG_78}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{AN_APG_78}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{M299_4xAGM_114L}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{AN_APG_78}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "AH-64D_BLK_II", -} -return unitPayloads diff --git a/resources/customized_payloads/AJS37.lua b/resources/customized_payloads/AJS37.lua deleted file mode 100644 index 9fe5c2519..000000000 --- a/resources/customized_payloads/AJS37.lua +++ /dev/null @@ -1,174 +0,0 @@ -local unitPayloads = { - ["name"] = "AJS37", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{RB75}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{RB75}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{RB75}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{RB75}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{Robot24J}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{Robot24J}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{VIGGEN_X-TANK}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{Robot74}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{Robot74}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AKAN}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{AKAN}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{VIGGEN_X-TANK}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{Robot24}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{Robot24}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{Rb15}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{Rb15}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{Robot74}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{Robot74}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{VIGGEN_X-TANK}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{M71BOMBD}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{M71BOMBD}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{M71BOMBD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{M71BOMBD}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{VIGGEN_X-TANK}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{Robot24J}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{Robot24J}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{BK90MJ1}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{BK90MJ1}", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "{VIGGEN_X-TANK}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{Robot74}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{Robot74}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "AJS37", -} -return unitPayloads diff --git a/resources/customized_payloads/AV8BNA.lua b/resources/customized_payloads/AV8BNA.lua deleted file mode 100644 index 91887bbb4..000000000 --- a/resources/customized_payloads/AV8BNA.lua +++ /dev/null @@ -1,334 +0,0 @@ -local unitPayloads = { - ["name"] = "AV8BNA", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{BRU-70A_3*GBU-54}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{BRU-70A_3*GBU-54}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{LAU_7_AGM_122_SIDEARM}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{LAU_7_AGM_122_SIDEARM}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{ALQ_164_RF_Jammer}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BRU-70A_3*GBU-54}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{BRU-70A_2*GBU-54_RIGHT}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{BRU-70A_2*GBU-54_LEFT}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{BRU-70A_3*GBU-54}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{BRU-42_2*GBU-38_LEFT}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{BRU-42_3*GBU-38}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{BRU-42_2*GBU-38_RIGHT}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BRU-42_3*GBU-38}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [7] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [8] = { - ["displayName"] = "Liberation SEAD Escort", - ["name"] = "Liberation SEAD Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AGM_122_SIDEARM}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{GBU_32_V_2B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "AV8BNA", -} -return unitPayloads diff --git a/resources/customized_payloads/B-17G.lua b/resources/customized_payloads/B-17G.lua deleted file mode 100644 index afc82a21e..000000000 --- a/resources/customized_payloads/B-17G.lua +++ /dev/null @@ -1,69 +0,0 @@ -local unitPayloads = { - ["name"] = "B-17G", - ["payloads"] = { - [1] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12xM64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12xM64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12xM64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12xM64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12xM64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "B-17G", -} -return unitPayloads diff --git a/resources/customized_payloads/B-1B.lua b/resources/customized_payloads/B-1B.lua deleted file mode 100644 index 32b67187e..000000000 --- a/resources/customized_payloads/B-1B.lua +++ /dev/null @@ -1,207 +0,0 @@ -local unitPayloads = { - ["name"] = "B-1B", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [2] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "CBU97*10", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "CBU97*10", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "CBU97*10", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [4] = { - ["name"] = "CAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 33, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "GBU-31V3B*8", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [6] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [7] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [8] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [9] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "GBU-31*8", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 34, - [2] = 32, - }, - }, - [10] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - }, - ["unitType"] = "B-1B", -} -return unitPayloads diff --git a/resources/customized_payloads/B-52H.lua b/resources/customized_payloads/B-52H.lua deleted file mode 100644 index 9a1fe690a..000000000 --- a/resources/customized_payloads/B-52H.lua +++ /dev/null @@ -1,85 +0,0 @@ -local unitPayloads = { - ["name"] = "B-52H", - ["payloads"] = { - [1] = { - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{6C47D097-83FF-4FB2-9496-EAB36DDF0B05}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{696CFFC4-0BDE-42A8-BE4B-0BE3D9DD723C}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{45447F82-01B5-4029-A572-9AAD28AF0275}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{8DCAF3A3-7FCF-41B8-BB88-58DEDA878EDE}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{45447F82-01B5-4029-A572-9AAD28AF0275}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HSAB-6xAGM-84}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{HSAB-6xAGM-84}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{6C47D097-83FF-4FB2-9496-EAB36DDF0B05}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{585D626E-7F42-4073-AB70-41E728C333E2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "B-52H", -} -return unitPayloads diff --git a/resources/customized_payloads/Bf-109K-4.lua b/resources/customized_payloads/Bf-109K-4.lua deleted file mode 100644 index b44c39f39..000000000 --- a/resources/customized_payloads/Bf-109K-4.lua +++ /dev/null @@ -1,137 +0,0 @@ -local unitPayloads = { - ["name"] = "Bf-109K-4", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Bf-109K-4", -} -return unitPayloads diff --git a/resources/customized_payloads/Bronco-OV-10A.lua b/resources/customized_payloads/Bronco-OV-10A.lua deleted file mode 100644 index b3b3469e6..000000000 --- a/resources/customized_payloads/Bronco-OV-10A.lua +++ /dev/null @@ -1,173 +0,0 @@ -local unitPayloads = { - ["name"] = "Bronco-OV-10A", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{150gal}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{150gal}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{150gal}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{150gal}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-9P-ON-ADAPTER}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Bronco-OV-10A", -} -return unitPayloads diff --git a/resources/customized_payloads/C-101CC.lua b/resources/customized_payloads/C-101CC.lua deleted file mode 100644 index 0782a0fb4..000000000 --- a/resources/customized_payloads/C-101CC.lua +++ /dev/null @@ -1,153 +0,0 @@ -local unitPayloads = { - ["name"] = "C-101CC", - ["payloads"] = { - [1] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{1461CD18-429A-42A9-A21F-4C621ECD4573}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{1461CD18-429A-42A9-A21F-4C621ECD4573}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C-101-DEFA553}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 17, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C-101-DEFA553}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{A021F29D-18AB-4d3e-985C-FC9C60E35E9E}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{A021F29D-18AB-4d3e-985C-FC9C60E35E9E}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C-101-DEFA553}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C-101-DEFA553}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "C-101CC", -} -return unitPayloads diff --git a/resources/customized_payloads/F-117A.lua b/resources/customized_payloads/F-117A.lua deleted file mode 100644 index 503ed662d..000000000 --- a/resources/customized_payloads/F-117A.lua +++ /dev/null @@ -1,79 +0,0 @@ -local unitPayloads = { - ["name"] = "F-117A", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 33, - }, - }, - }, - ["unitType"] = "F-117A", -} -return unitPayloads diff --git a/resources/customized_payloads/F-14A-135-GR.lua b/resources/customized_payloads/F-14A-135-GR.lua deleted file mode 100644 index e50d97983..000000000 --- a/resources/customized_payloads/F-14A-135-GR.lua +++ /dev/null @@ -1,344 +0,0 @@ -local unitPayloads = { - ["name"] = "F-14A", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F14-LANTIRN-TP}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{PHXBRU3242_2*LAU10 LS}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F14-LANTIRN-TP}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM-7MH}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [4] = { - ["name"] = "BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{F14-LANTIRN-TP}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{PHXBRU3242_2*LAU10 LS}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{BRU-32 MK-82}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BRU-32 MK-20}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{BRU-32 MK-20}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{F14-LANTIRN-TP}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [3] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{PHXBRU3242_2*LAU10 LS}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{BRU-32 GBU-16}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 6, - }, - [8] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 5, - }, - [9] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [10] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [6] = { - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{MAK79_MK82 4}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{MAK79_MK82 3R}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{MAK79_MK82 3L}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{MAK79_MK82 4}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [7] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "F-14A-135-GR", -} -return unitPayloads diff --git a/resources/customized_payloads/F-14B.lua b/resources/customized_payloads/F-14B.lua deleted file mode 100644 index 833917424..000000000 --- a/resources/customized_payloads/F-14B.lua +++ /dev/null @@ -1,308 +0,0 @@ -local unitPayloads = { - ["name"] = "F-14B", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{SHOULDER AIM-7MH}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{AIM_54C_Mk47}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{SHOULDER AIM-7MH}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 18, - [4] = 19, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PHXBRU3242_2*LAU10 RS}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{BRU3242_LAU10}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{BRU-32 GBU-12}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{BRU-32 GBU-12}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{BRU3242_2*LAU10 R}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{PHXBRU3242_2*LAU10 LS}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 18, - [4] = 19, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 18, - [4] = 19, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{BRU-32 MK-83}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 18, - [4] = 19, - }, - }, - [5] = { - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{MAK79_MK82 4}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{MAK79_MK82 3R}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{MAK79_MK82 3L}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{MAK79_MK82 4}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 L}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{SHOULDER AIM_54C_Mk47 R}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{F14-300gal}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{BRU3242_ADM141}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "F-14B", -} -return unitPayloads diff --git a/resources/customized_payloads/F-15C.lua b/resources/customized_payloads/F-15C.lua deleted file mode 100644 index 3362ccf52..000000000 --- a/resources/customized_payloads/F-15C.lua +++ /dev/null @@ -1,277 +0,0 @@ -local unitPayloads = { - ["name"] = "F-15C", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - }, - ["unitType"] = "F-15C", -} -return unitPayloads diff --git a/resources/customized_payloads/F-15E.lua b/resources/customized_payloads/F-15E.lua deleted file mode 100644 index ae0de2be1..000000000 --- a/resources/customized_payloads/F-15E.lua +++ /dev/null @@ -1,388 +0,0 @@ -local unitPayloads = { - ["name"] = "F-15E", - ["payloads"] = { - [1] = { - ["displayName"] = "CAS", - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{CBU_105}", - ["num"] = 11, - }, - [9] = { - ["CLSID"] = "{CBU_105}", - ["num"] = 12, - }, - [10] = { - ["CLSID"] = "{CBU_105}", - ["num"] = 13, - }, - [11] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [12] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [13] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 13, - }, - [7] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [8] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 12, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [10] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 9, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - [6] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 13, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{51F9AAE5-964F-4D21-83FB-502E3BFE5F8A}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{51F9AAE5-964F-4D21-83FB-502E3BFE5F8A}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [7] = { - ["CLSID"] = "{51F9AAE5-964F-4D21-83FB-502E3BFE5F8A}", - ["num"] = 13, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [9] = { - ["CLSID"] = "{51F9AAE5-964F-4D21-83FB-502E3BFE5F8A}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - [6] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 11, - }, - [7] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [8] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 12, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [10] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 9, - }, - [11] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 13, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [6] = { - ["name"] = "OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [10] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 9, - }, - [11] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 13, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["name"] = "OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 13, - }, - [11] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 14, - }, - [12] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 16, - }, - [13] = { - ["CLSID"] = "{E1F29B21-F291-4589-9FD8-3272EEC69506}", - ["num"] = 18, - }, - [14] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 19, - }, - [15] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 17, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "F-15E", -} -return unitPayloads diff --git a/resources/customized_payloads/F-15ESE.lua b/resources/customized_payloads/F-15ESE.lua deleted file mode 100644 index 1f328a6ea..000000000 --- a/resources/customized_payloads/F-15ESE.lua +++ /dev/null @@ -1,561 +0,0 @@ -local unitPayloads = { - ["name"] = "F-15ESE", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 14, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [12] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 2, - }, - [13] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 14, - }, - [9] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{CFT_R_GBU_31V3B_x_2}", - ["num"] = 12, - }, - [11] = { - ["CLSID"] = "{CFT_L_GBU_31V3B_x_2}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{CFT_L_GBU_31V3B_x_2}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{CFT_R_GBU_31V3B_x_2}", - ["num"] = 12, - }, - [6] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [7] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [10] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 14, - }, - [11] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 14, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [12] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 2, - }, - [13] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{CFT_L_GBU_31V3B_x_2}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 14, - }, - [11] = { - ["CLSID"] = "{CFT_R_GBU_31V3B_x_2}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [6] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 14, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [12] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 2, - }, - [13] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [7] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{CFT_L_GBU_38_x_3}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 14, - }, - [10] = { - ["CLSID"] = "{CFT_R_GBU_38_x_3}", - ["num"] = 12, - }, - [11] = { - ["CLSID"] = "{GBU-38}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [8] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 14, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 11, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [12] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 2, - }, - [13] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [9] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{CFT_L_GBU_31V3B_x_2}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{CFT_R_GBU_31V3B_x_2}", - ["num"] = 12, - }, - [10] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 14, - }, - [11] = { - ["CLSID"] = "{GBU-31V3B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 15, - }, - [2] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 13, - }, - [3] = { - ["CLSID"] = "{CFT_R_BLU107_x_6}", - ["num"] = 12, - }, - [4] = { - ["CLSID"] = "{F-15E_AAQ-13_LANTIRN}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{F-15E_AAQ-14_LANTIRN}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{CFT_L_BLU107_x_6}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{F15E_EXTTANK}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "F-15ESE", -} -return unitPayloads diff --git a/resources/customized_payloads/F-16A.lua b/resources/customized_payloads/F-16A.lua deleted file mode 100644 index 4f6aca035..000000000 --- a/resources/customized_payloads/F-16A.lua +++ /dev/null @@ -1,226 +0,0 @@ -local unitPayloads = { - ["name"] = "F-16A", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 10, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 7, - }, }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 10, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 10, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{7B8DCEB4-820B-4015-9B48-1028A4195692}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{7B8DCEB4-820B-4015-9B48-1028A4195692}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 10, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "ALQ_184", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{C8E06185-7CD6-4C90-959F-044679E90751}", - ["num"] = 10, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "F-16A", -} -return unitPayloads diff --git a/resources/customized_payloads/F-16C_50.lua b/resources/customized_payloads/F-16C_50.lua deleted file mode 100644 index 293700022..000000000 --- a/resources/customized_payloads/F-16C_50.lua +++ /dev/null @@ -1,374 +0,0 @@ -local unitPayloads = { - ["name"] = "F-16C_50", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "ALQ_184_Long", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{DAC53A2F-79CA-42FF-A77A-F5649B601308}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - [8] = { - ["CLSID"] = "ALQ_184", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{GBU-31}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "ALQ_184", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [5] = { - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "ALQ_184", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - [7] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [11] = { - ["CLSID"] = "{AN_ASQ_213}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [6] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{AGM-154A}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{AGM-154A}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "ALQ_184", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{AN_ASQ_213}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [7] = { - ["name"] = "Liberation Ferry", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "MXU-648-TP", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "MXU-648-TP", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{8A0BE8AE-58D4-4572-9263-3144C0D06364}", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [8] = { - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "ALQ_184", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{F376DBEE-4CAE-41BA-ADD9-B2910AC95DEC}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "F-16C_50", -} -return unitPayloads diff --git a/resources/customized_payloads/F-22A.lua b/resources/customized_payloads/F-22A.lua deleted file mode 100644 index 6733e61fc..000000000 --- a/resources/customized_payloads/F-22A.lua +++ /dev/null @@ -1,409 +0,0 @@ -local unitPayloads = { - ["name"] = "F-22A", - ["payloads"] = { - [1] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["name"] = "RUNWAY_ATTACK", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "INTERCEPT", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{AIM-120D}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 1, - }, - [8] = { - ["CLSID"] = "{AIM-9XX}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "F-22A", -} -return unitPayloads diff --git a/resources/customized_payloads/F-4E.lua b/resources/customized_payloads/F-4E.lua deleted file mode 100644 index 4c73fb347..000000000 --- a/resources/customized_payloads/F-4E.lua +++ /dev/null @@ -1,221 +0,0 @@ -local unitPayloads = { - ["name"] = "F-4E", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{7B4B122D-C12C-4DB4-834E-4D8BB4D863A8}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{9DDF5297-94B9-42FC-A45E-6E316121CD85}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{9DDF5297-94B9-42FC-A45E-6E316121CD85}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{7B4B122D-C12C-4DB4-834E-4D8BB4D863A8}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{8B9E3FD0-F034-4A07-B6CE-C269884CC71B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{1C97B4A0-AA3B-43A8-8EE7-D11071457185}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{1C97B4A0-AA3B-43A8-8EE7-D11071457185}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{8B9E3FD0-F034-4A07-B6CE-C269884CC71B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98453}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{E6A6262A-CA08-4B3D-B030-E1A993B98452}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515405}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{8D399DDA-FF81-4F14-904D-099B34FE7918}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{8B9E3FD0-F034-4A07-B6CE-C269884CC71B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "F-4E", -} -return unitPayloads diff --git a/resources/customized_payloads/F-5E-3.lua b/resources/customized_payloads/F-5E-3.lua deleted file mode 100644 index 7aeace2bd..000000000 --- a/resources/customized_payloads/F-5E-3.lua +++ /dev/null @@ -1,171 +0,0 @@ -local unitPayloads = { - ["name"] = "F-5E-3", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{PTB-150GAL}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{PTB-150GAL}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{PTB-150GAL}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0395076D-2F77-4420-9D33-087A4398130B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AIM-9P5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{PTB-150GAL}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{LAU68_FFAR_MK5HEAT}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "F-5E-3", -} -return unitPayloads diff --git a/resources/customized_payloads/F-86F Sabre.lua b/resources/customized_payloads/F-86F Sabre.lua deleted file mode 100644 index db63458cb..000000000 --- a/resources/customized_payloads/F-86F Sabre.lua +++ /dev/null @@ -1,248 +0,0 @@ -local unitPayloads = { - ["name"] = "F-86F Sabre", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 8, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{GAR-8}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{GAR-8}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{PTB_120_F86F35}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{PTB_120_F86F35}", - ["num"] = 4, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 8, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 4, - }, - }, - ["tasks"] = { - }, - }, - [6] = { - ["name"] = "INTERCEPT", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_120_F86F35}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{PTB_120_F86F35}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{GAR-8}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{GAR-8}", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [7] = { - ["name"] = "RUNWAY_ATTACK", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{00F5DAC4-0466-4122-998F-B1A298E34113}", - ["num"] = 4, - }, - }, - ["tasks"] = { - }, - }, - [8] = { - ["name"] = "BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 3, - }, - }, - ["tasks"] = { - }, - }, - [9] = { - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{PTB_200_F86F35}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVARx2}", - ["num"] = 3, - }, - }, - ["tasks"] = { - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "F-86F Sabre", -} -return unitPayloads diff --git a/resources/customized_payloads/FA-18C_hornet.lua b/resources/customized_payloads/FA-18C_hornet.lua deleted file mode 100644 index 3865947f2..000000000 --- a/resources/customized_payloads/FA-18C_hornet.lua +++ /dev/null @@ -1,298 +0,0 @@ -local unitPayloads = { - ["name"] = "FA-18C_hornet", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "LAU-115_2*LAU-127_AIM-120C", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "LAU-115_2*LAU-127_AIM-120C", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "LAU_117_AGM_65F", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{AN_ASQ_228}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{GBU_31_V_2B}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN_ASQ_228}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{GBU_31_V_2B}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AGM_84D}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{AGM_84D}", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{AN_ASQ_228}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{AGM_84D}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{AGM_84D}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [6] = { - ["name"] = "RUNWAY_ATTACK", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BRU33_2X_MK-82}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{BRU33_2X_MK-82}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{BRU33_2X_MK-82}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 34, - }, - }, - [7] = { - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{5CE2FF2A-645A-4197-B48D-8720AC69394F}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{FPU_8A_FUEL_TANK}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{BRU55_2*AGM-154A}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{BRU55_2*AGM-154A}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{AN_ASQ_228}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "FA-18C_hornet", -} -return unitPayloads diff --git a/resources/customized_payloads/FW-190A8.lua b/resources/customized_payloads/FW-190A8.lua deleted file mode 100644 index 5536b229c..000000000 --- a/resources/customized_payloads/FW-190A8.lua +++ /dev/null @@ -1,137 +0,0 @@ -local unitPayloads = { - ["name"] = "FW-190A8", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "BF109K_4_FUEL_TANK", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB_500_1_SD_10A}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB_500_1_SD_10A}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB_500_1_SD_10A}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "FW-190A8", -} -return unitPayloads diff --git a/resources/customized_payloads/FW-190D9.lua b/resources/customized_payloads/FW-190D9.lua deleted file mode 100644 index 69ad72978..000000000 --- a/resources/customized_payloads/FW-190D9.lua +++ /dev/null @@ -1,169 +0,0 @@ -local unitPayloads = { - ["name"] = "FW-190D9", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "FW109_FUEL_TANK", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FW_190_R4M_RGHT_WING}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FW_190_R4M_LEFT_WING}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "FW109_FUEL_TANK", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FW_190_R4M_RGHT_WING}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FW_190_R4M_LEFT_WING}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "FW109_FUEL_TANK", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FW_190_R4M_RGHT_WING}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FW_190_R4M_LEFT_WING}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "FW109_FUEL_TANK", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FW_190_R4M_RGHT_WING}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FW_190_R4M_LEFT_WING}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "ER_4_SC50", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "SC_501_SC500", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "FW-190D9", -} -return unitPayloads diff --git a/resources/customized_payloads/H-6J.lua b/resources/customized_payloads/H-6J.lua deleted file mode 100644 index 4c7a34f4f..000000000 --- a/resources/customized_payloads/H-6J.lua +++ /dev/null @@ -1,278 +0,0 @@ -local unitPayloads = { - ["name"] = "H-6J", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_H6_250_2_N24", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "DIS_GDJ_YJ83K", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_H6_250_2_N24", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [6] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "DIS_DF4A_KD20", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_H6_250_2_N24", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "DIS_AKG_DLPOD", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "DIS_MER6_250_3_N6", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "H-6J", -} -return unitPayloads diff --git a/resources/customized_payloads/Hercules.lua b/resources/customized_payloads/Hercules.lua deleted file mode 100644 index 9f2012f6d..000000000 --- a/resources/customized_payloads/Hercules.lua +++ /dev/null @@ -1,129 +0,0 @@ -local unitPayloads = { - ["name"] = "Hercules", - ["payloads"] = { - [1] = { - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [7] = { - ["name"] = "CAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [8] = { - ["name"] = "RUNWAY_STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "Herc_Soldier_Squad", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "Herc_GBU-43/B(MOAB)", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Hercules", -} -return unitPayloads diff --git a/resources/customized_payloads/I-16.lua b/resources/customized_payloads/I-16.lua deleted file mode 100644 index 35337ee12..000000000 --- a/resources/customized_payloads/I-16.lua +++ /dev/null @@ -1,198 +0,0 @@ -local unitPayloads = { - ["name"] = "I-16", - ["payloads"] = { - [1] = { - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "I16_DROP_FUEL_TANK", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "I16_RS_82", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "I16_FAB_100SV", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "I-16", -} -return unitPayloads diff --git a/resources/customized_payloads/J-11A.lua b/resources/customized_payloads/J-11A.lua deleted file mode 100644 index 6310a08ee..000000000 --- a/resources/customized_payloads/J-11A.lua +++ /dev/null @@ -1,250 +0,0 @@ -local unitPayloads = { - ["name"] = "J-11A", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 10, - [4] = 11, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{TWIN_B13L_5OF}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{F99BEC1A-869D-4AC7-9730-FBA0E3B1F5FC}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{F99BEC1A-869D-4AC7-9730-FBA0E3B1F5FC}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{TWIN_B13L_5OF}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "J-11A", -} -return unitPayloads diff --git a/resources/customized_payloads/JAS39Gripen.lua b/resources/customized_payloads/JAS39Gripen.lua deleted file mode 100644 index 98a8b3a61..000000000 --- a/resources/customized_payloads/JAS39Gripen.lua +++ /dev/null @@ -1,54 +0,0 @@ -local unitPayloads = { - ["name"] = "JAS39Gripen", - ["payloads"] = { - [1] = { - ["displayName"] = "CAP", - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [3] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [4] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{JAS39_Meteor}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{JAS39_Meteor}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{JAS39_Meteor}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{JAS39_Meteor}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "JAS39Gripen", -} -return unitPayloads diff --git a/resources/customized_payloads/JAS39Gripen_AG.lua b/resources/customized_payloads/JAS39Gripen_AG.lua deleted file mode 100644 index 89e69c4b6..000000000 --- a/resources/customized_payloads/JAS39Gripen_AG.lua +++ /dev/null @@ -1,303 +0,0 @@ -local unitPayloads = { - ["name"] = "JAS39Gripen_AG", - ["payloads"] = { - [1] = { - ["displayName"] = "ANTISHIP", - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_RBS15AI}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{JAS39_RBS15AI}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{JAS39_RBS15AI}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{JAS39_RBS15AI}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [2] = { - ["displayName"] = "SEAD", - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [3] = { - ["displayName"] = "DEAD", - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_STORMSHADOW_ARM}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{JAS39_STORMSHADOW_ARM}", - ["num"] = 6, - }, - [8] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{JAS39_MAR-1}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [4] = { - ["displayName"] = "CAS", - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_BRIMSTONE}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{JAS39_BRIMSTONE}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{JAS39_BRIMSTONE}", - ["num"] = 6, - }, - [9] = { - ["CLSID"] = "{JAS39_BRIMSTONE}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{JAS39_Litening}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{JAS39_FLIR}", - ["num"] = 9 - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [5] = { - ["displayName"] = "STRIKE", - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_GBU31}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{JAS39_GBU31}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{JAS39_GBU49}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{JAS39_GBU49}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{JAS39_Litening}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{JAS39_FLIR}", - ["num"] = 9 - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [6] = { - ["displayName"] = "OCA", - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{JAS39_IRIS-T}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{JAS39_TANK1100}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{JAS39_ELINT}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{JAS39_EWS39}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{JAS39_DWS39_TV}", - ["num"] = 2, - }, - [7] = { - ["CLSID"] = "{JAS39_DWS39_TV}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{JAS39_M70BHE}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{JAS39_M70BHE}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{JAS39_Litening}", - ["num"] = 5, - }, - [11] = { - ["CLSID"] = "{JAS39_FLIR}", - ["num"] = 9 - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "JAS39Gripen_AG", -} -return unitPayloads diff --git a/resources/customized_payloads/JF-17.lua b/resources/customized_payloads/JF-17.lua deleted file mode 100644 index b4c0e4b55..000000000 --- a/resources/customized_payloads/JF-17.lua +++ /dev/null @@ -1,223 +0,0 @@ -local unitPayloads = { - ["name"] = "JF-17", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_WMD7", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "DIS_BRM1_90", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "DIS_BRM1_90", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_LS_6_500", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "DIS_LS_6_500", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "DIS_LS_6_500", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "DIS_LS_6_500", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "DIS_SPJ_POD", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "DIS_SD-10_DUAL_R", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "DIS_SD-10_DUAL_L", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_SPJ_POD", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "DIS_LD-10_DUAL_R", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "DIS_LD-10_DUAL_L", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_WMD7", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "DIS_SD-10_DUAL_R", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "DIS_SD-10_DUAL_L", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "DIS_C-802AK", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "DIS_C-802AK", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - [6] = { - ["name"] = "RUNWAY_ATTACK", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_TYPE200_DUAL_R", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "DIS_TANK800", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "DIS_TYPE200_DUAL_L", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "DIS_PL-5EII", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "DIS_WMD7", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 10, - [2] = 11, - [3] = 19, - }, - }, - }, - ["unitType"] = "JF-17", -} -return unitPayloads diff --git a/resources/customized_payloads/Ju-88A4.lua b/resources/customized_payloads/Ju-88A4.lua deleted file mode 100644 index 982328ed4..000000000 --- a/resources/customized_payloads/Ju-88A4.lua +++ /dev/null @@ -1,126 +0,0 @@ -local unitPayloads = { - ["name"] = "Ju-88A4", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LTF_5B}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{LTF_5B}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB_500_1_SD_10A}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AB_500_1_SD_10A}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [6] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{SC_500_L2}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Ju-88A4", -} -return unitPayloads diff --git a/resources/customized_payloads/Ka-50.lua b/resources/customized_payloads/Ka-50.lua deleted file mode 100644 index 69c3a1925..000000000 --- a/resources/customized_payloads/Ka-50.lua +++ /dev/null @@ -1,106 +0,0 @@ -local unitPayloads = { - ["name"] = "Ka-50", - ["payloads"] = { - [1] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "Ka-50", -} -return unitPayloads diff --git a/resources/customized_payloads/Ka-50_3.lua b/resources/customized_payloads/Ka-50_3.lua deleted file mode 100644 index 90ea41046..000000000 --- a/resources/customized_payloads/Ka-50_3.lua +++ /dev/null @@ -1,140 +0,0 @@ -local unitPayloads = { - ["name"] = "Ka-50_3", - ["payloads"] = { - [1] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "B_8V20A_OFP2", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{9S846_2xIGLA}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{A6FD14D3-6D30-4C85-88A7-8D17BEE120E2}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Ka-50_3", -} -return unitPayloads diff --git a/resources/customized_payloads/L-39C.lua b/resources/customized_payloads/L-39C.lua deleted file mode 100644 index 6a273015b..000000000 --- a/resources/customized_payloads/L-39C.lua +++ /dev/null @@ -1,101 +0,0 @@ -local unitPayloads = { - ["name"] = "L-39C", - ["payloads"] = { - [1] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 30, - [3] = 32, - [4] = 34, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 30, - [3] = 32, - [4] = 34, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 30, - [3] = 32, - [4] = 34, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 30, - [3] = 32, - [4] = 34, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R-3S}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{R-3S}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "L-39C", -} -return unitPayloads diff --git a/resources/customized_payloads/L-39ZA.lua b/resources/customized_payloads/L-39ZA.lua deleted file mode 100644 index 5f9263bce..000000000 --- a/resources/customized_payloads/L-39ZA.lua +++ /dev/null @@ -1,137 +0,0 @@ -local unitPayloads = { - ["name"] = "L-39ZA", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{APU-60-1_R_60M}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{APU-60-1_R_60M}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{PK-3}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{PK-3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - [2] = 31, - [3] = 32, - [4] = 34, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - [2] = 31, - [3] = 32, - [4] = 34, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{UB-16-57UMP}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - [2] = 31, - [3] = 32, - [4] = 34, - }, - }, - }, - ["unitType"] = "L-39ZA", -} -return unitPayloads diff --git a/resources/customized_payloads/M-2000C.lua b/resources/customized_payloads/M-2000C.lua deleted file mode 100644 index 3f015947d..000000000 --- a/resources/customized_payloads/M-2000C.lua +++ /dev/null @@ -1,265 +0,0 @@ -local unitPayloads = { - ["name"] = "M-2000C", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{Matra_S530D}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{Matra_S530D}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{M2KC_RPL_522}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{Matra155RocketPod}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{Matra155RocketPod}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{Matra155RocketPod}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{Matra155RocketPod}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{M2KC_RPL_522}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{M2KC_RPL_522}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{M2KC_RPL_522}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{M2KC_RAFAUT_MK82}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{M2KC_RPL_522}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["name"] = "RUNWAY_ATTACK", - ["pylons"] = { - [1] = { - ["CLSID"] = "{Eclair}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{MMagicII}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 34, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "M-2000C", -} -return unitPayloads diff --git a/resources/customized_payloads/MB-339A.lua b/resources/customized_payloads/MB-339A.lua deleted file mode 100644 index 29278eb1f..000000000 --- a/resources/customized_payloads/MB-339A.lua +++ /dev/null @@ -1,214 +0,0 @@ -local unitPayloads = { - ["name"] = "MB-339A", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-R}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-L}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{MB339_DEFA553_R}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{MB339_DEFA553_L}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-R}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-L}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{MB339_DEFA553_R}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{MB339_DEFA553_L}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-R}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-L}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{LR25_ARF8M3_API}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{LR25_ARF8M3_API}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{MB339_DEFA553_R}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{MB339_DEFA553_L}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-R}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-L}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{MB339_DEFA553_R}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{MB339_DEFA553_L}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BLG66_BELOUGA_AC}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-R}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FUEL-TIP-ELLITTIC-L}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 9, - }, - [4] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{Mk82SNAKEYE}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MB-339A", -} -return unitPayloads diff --git a/resources/customized_payloads/MQ-9 Reaper.lua b/resources/customized_payloads/MQ-9 Reaper.lua deleted file mode 100644 index 3fcba86ce..000000000 --- a/resources/customized_payloads/MQ-9 Reaper.lua +++ /dev/null @@ -1,33 +0,0 @@ -local unitPayloads = { - ["name"] = "MQ-9 Reaper", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 17, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MQ-9 Reaper", -} -return unitPayloads diff --git a/resources/customized_payloads/Mi-24P.lua b/resources/customized_payloads/Mi-24P.lua deleted file mode 100644 index fad0d3832..000000000 --- a/resources/customized_payloads/Mi-24P.lua +++ /dev/null @@ -1,217 +0,0 @@ -local unitPayloads = { - ["name"] = "Mi-24P", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 18, - [3] = 32, - }, - }, - [2] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 18, - [3] = 32, - }, - }, - [3] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation Antiship", - ["name"] = "Liberation Antiship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 18, - [3] = 32, - }, - }, - [5] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 18, - [3] = 32, - }, - }, - [6] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 18, - [3] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mi-24P", -} -return unitPayloads diff --git a/resources/customized_payloads/Mi-24V.lua b/resources/customized_payloads/Mi-24V.lua deleted file mode 100644 index c5cbd5bae..000000000 --- a/resources/customized_payloads/Mi-24V.lua +++ /dev/null @@ -1,148 +0,0 @@ -local unitPayloads = { - ["name"] = "Mi-24V", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - [4] = 30, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - [4] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{B919B0F4-7C25-455E-9A02-CEA51DB895E3}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - [4] = 30, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - }, - }, - }, - ["unitType"] = "Mi-24V", -} -return unitPayloads diff --git a/resources/customized_payloads/Mi-28.lua b/resources/customized_payloads/Mi-28.lua deleted file mode 100644 index 35d434bad..000000000 --- a/resources/customized_payloads/Mi-28.lua +++ /dev/null @@ -1,131 +0,0 @@ -local unitPayloads = { - ["name"] = "Mi-28", - ["payloads"] = { - [1] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - [4] = 30, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - [4] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{57232979-8B0F-4db7-8D9A-55197E06B0F5}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 18, - }, - }, - }, - ["unitType"] = "Mi-28N", -} -return unitPayloads diff --git a/resources/customized_payloads/Mi-8MT.lua b/resources/customized_payloads/Mi-8MT.lua deleted file mode 100644 index 3e22cd4ed..000000000 --- a/resources/customized_payloads/Mi-8MT.lua +++ /dev/null @@ -1,201 +0,0 @@ -local unitPayloads = { - ["name"] = "Mi-8MT", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "PKT_7_62", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "KORD_12_7", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 35, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "PKT_7_62", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "KORD_12_7", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 35, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "PKT_7_62", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "KORD_12_7", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{05544F1A-C39C-466b-BC37-5BD1D52E57BB}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 35, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "PKT_7_62", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "KORD_12_7", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 35, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "PKT_7_62", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "KORD_12_7", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "GUV_VOG", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{6A4B9E69-64FE-439a-9163-3A87FB6A4D81}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 35, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mi-8MT", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-15bis.lua b/resources/customized_payloads/MiG-15bis.lua deleted file mode 100644 index 74023ad8e..000000000 --- a/resources/customized_payloads/MiG-15bis.lua +++ /dev/null @@ -1,84 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-15bis", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "PTB300_MIG15", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "PTB300_MIG15", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "FAB_50", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "FAB_50", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "FAB_50", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "FAB_50", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "FAB_100M", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "FAB_100M", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "FAB_100M", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "FAB_100M", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MiG-15bis", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-19P.lua b/resources/customized_payloads/MiG-19P.lua deleted file mode 100644 index 84e6c4793..000000000 --- a/resources/customized_payloads/MiG-19P.lua +++ /dev/null @@ -1,161 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-19P", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{K-13A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{K-13A}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB760_MIG19", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "PTB760_MIG19", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{K-13A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{K-13A}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{K-13A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{K-13A}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{K-13A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{K-13A}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{K-13A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{K-13A}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ORO57K_S5M_HEFRAG}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MiG-19P", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-21bis.lua b/resources/customized_payloads/MiG-21bis.lua deleted file mode 100644 index 36934bb6a..000000000 --- a/resources/customized_payloads/MiG-21bis.lua +++ /dev/null @@ -1,169 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-21Bis", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_490C_MIG21}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{R-3R}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{R-3R}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{R-60 2L}", - ["num"] = 1, - }, - [5] = { - ["CLSID"] = "{R-60 2R}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{ASO-2}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ASO-2}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{S-24B}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{UB-32_S5M}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{UB-32_S5M}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{S-24B}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{PTB_490C_MIG21}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ASO-2}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{S-24B}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{Kh-66_Grom}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{Kh-66_Grom}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{S-24B}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{PTB_490C_MIG21}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ASO-2}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{S-24B}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{Kh-66_Grom}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{Kh-66_Grom}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{S-24B}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{PTB_490C_MIG21}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{PTB_800_MIG21}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{35B698AC-9FEF-4EC4-AD29-484A0085F62B}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{35B698AC-9FEF-4EC4-AD29-484A0085F62B}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{ASO-2}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 1, - }, - [6] = { - ["CLSID"] = "{FB3CE165-BF07-4979-887C-92B87F13276B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MiG-21Bis", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-23MLD.lua b/resources/customized_payloads/MiG-23MLD.lua deleted file mode 100644 index 080649bb0..000000000 --- a/resources/customized_payloads/MiG-23MLD.lua +++ /dev/null @@ -1,143 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-23MLD", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{CCF898C9-5BC7-49A4-9D1E-C3ED3D5166A1}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{275A2855-4A79-4B2D-B082-91EA2ADF4691}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{CCF898C9-5BC7-49A4-9D1E-C3ED3D5166A1}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "MiG-23MLD", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-25PD.lua b/resources/customized_payloads/MiG-25PD.lua deleted file mode 100644 index ee6bafcc5..000000000 --- a/resources/customized_payloads/MiG-25PD.lua +++ /dev/null @@ -1,142 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-25PD", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{5F26DBC2-FB43-4153-92DE-6BBCE26CB0FF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{5F26DBC2-FB43-4153-92DE-6BBCE26CB0FF}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - }, - ["unitType"] = "MiG-25PD", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-27K.lua b/resources/customized_payloads/MiG-27K.lua deleted file mode 100644 index bda195a8f..000000000 --- a/resources/customized_payloads/MiG-27K.lua +++ /dev/null @@ -1,158 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-27K", - ["payloads"] = { - [1] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{E659C4BE-2CD8-4472-8C08-3F28ACB61A8A}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{E659C4BE-2CD8-4472-8C08-3F28ACB61A8A}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 8, - }, - }, - ["tasks"] = { - }, - }, - }, - ["unitType"] = "MiG-27K", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-29A.lua b/resources/customized_payloads/MiG-29A.lua deleted file mode 100644 index 39d225062..000000000 --- a/resources/customized_payloads/MiG-29A.lua +++ /dev/null @@ -1,183 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-29A", - ["payloads"] = { - [1] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "MiG-29A", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-29G.lua b/resources/customized_payloads/MiG-29G.lua deleted file mode 100644 index 3167fc756..000000000 --- a/resources/customized_payloads/MiG-29G.lua +++ /dev/null @@ -1,171 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-29G", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - }, - ["unitType"] = "MiG-29G", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-29S.lua b/resources/customized_payloads/MiG-29S.lua deleted file mode 100644 index 1ea78e972..000000000 --- a/resources/customized_payloads/MiG-29S.lua +++ /dev/null @@ -1,187 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-29S", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 10, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{2BEC576B-CDF5-4B7F-961F-B0FA4312B841}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "MiG-29S", -} -return unitPayloads diff --git a/resources/customized_payloads/MiG-31.lua b/resources/customized_payloads/MiG-31.lua deleted file mode 100644 index a714f9647..000000000 --- a/resources/customized_payloads/MiG-31.lua +++ /dev/null @@ -1,182 +0,0 @@ -local unitPayloads = { - ["name"] = "MiG-31", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{F1243568-8EF0-49D4-9CB5-4DA90D92BC1D}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4EDBA993-2E34-444C-95FB-549300BF7CAF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - }, - ["unitType"] = "MiG-31", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage 2000-5.lua b/resources/customized_payloads/Mirage 2000-5.lua deleted file mode 100644 index ffb845eb3..000000000 --- a/resources/customized_payloads/Mirage 2000-5.lua +++ /dev/null @@ -1,242 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage 2000-5", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{414DA830-B61A-4F9E-B71B-C2F6832E1D7A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{414DA830-B61A-4F9E-B71B-C2F6832E1D7A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{414DA830-B61A-4F9E-B71B-C2F6832E1D7A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{414DA830-B61A-4F9E-B71B-C2F6832E1D7A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{414DA830-B61A-4F9E-B71B-C2F6832E1D7A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6D778860-7BB8-4ACB-9E95-BA772C6BBC2C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 10, - [3] = 18, - [4] = 19, - }, - }, - }, - ["unitType"] = "Mirage 2000-5", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1B.lua b/resources/customized_payloads/Mirage-F1B.lua deleted file mode 100644 index edbf6d055..000000000 --- a/resources/customized_payloads/Mirage-F1B.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1B", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1B", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1BE.lua b/resources/customized_payloads/Mirage-F1BE.lua deleted file mode 100644 index 2a335fab5..000000000 --- a/resources/customized_payloads/Mirage-F1BE.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1BE", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1BE", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1C-200.lua b/resources/customized_payloads/Mirage-F1C-200.lua deleted file mode 100644 index ab6ef612d..000000000 --- a/resources/customized_payloads/Mirage-F1C-200.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1C-200", - ["payloads"] = { - [1] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{R550_Magic_1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1C-200", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1CE.lua b/resources/customized_payloads/Mirage-F1CE.lua deleted file mode 100644 index eb282510e..000000000 --- a/resources/customized_payloads/Mirage-F1CE.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1CE", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1CE", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1CT.lua b/resources/customized_payloads/Mirage-F1CT.lua deleted file mode 100644 index 140fc6e77..000000000 --- a/resources/customized_payloads/Mirage-F1CT.lua +++ /dev/null @@ -1,346 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1CT", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{SAMP400LD}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1CT", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1EE.lua b/resources/customized_payloads/Mirage-F1EE.lua deleted file mode 100644 index 41f7db8d6..000000000 --- a/resources/customized_payloads/Mirage-F1EE.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1EE", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1EE", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1EQ.lua b/resources/customized_payloads/Mirage-F1EQ.lua deleted file mode 100644 index 66d307c5c..000000000 --- a/resources/customized_payloads/Mirage-F1EQ.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1EQ", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{FD21B13E-57F3-4C2A-9F78-C522D0B5BCE1}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1EQ", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1M-CE.lua b/resources/customized_payloads/Mirage-F1M-CE.lua deleted file mode 100644 index 3682e621d..000000000 --- a/resources/customized_payloads/Mirage-F1M-CE.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1M-CE", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1M-CE", -} -return unitPayloads diff --git a/resources/customized_payloads/Mirage-F1M-EE.lua b/resources/customized_payloads/Mirage-F1M-EE.lua deleted file mode 100644 index 060b07427..000000000 --- a/resources/customized_payloads/Mirage-F1M-EE.lua +++ /dev/null @@ -1,345 +0,0 @@ -local unitPayloads = { - ["name"] = "Mirage-F1M-EE", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "BR_500", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "BR_500", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "BR_500", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "BR_500", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{CLB4_BLU107}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLU107B_DURANDAL}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{BLG66_BELOUGA}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{R530F_EM}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "PTB-1200-F1", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Mirage-F1M-EE", -} -return unitPayloads diff --git a/resources/customized_payloads/MosquitoFBMkVI.lua b/resources/customized_payloads/MosquitoFBMkVI.lua deleted file mode 100644 index eb79fca96..000000000 --- a/resources/customized_payloads/MosquitoFBMkVI.lua +++ /dev/null @@ -1,286 +0,0 @@ -local unitPayloads = { - ["name"] = "MosquitoFBMkVI", - ["payloads"] = { - [1] = { - ["displayName"] = "500 lb GP Mk.V*2, 500 lb GP Short tail*2", - ["name"] = "500 lb GP Mk.V*2, 500 lb GP Short tail*2", - ["pylons"] = { - [1] = { - ["CLSID"] = "{British_GP_500LB_Bomb_Mk5}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{British_GP_500LB_Bomb_Mk5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_GP_500LB_Bomb_Mk4_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_GP_500LB_Bomb_Mk4_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - [2] = 32, - [3] = 31, - [4] = 34, - }, - }, - [2] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_RIGHT_WING_RAILS}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_LEFT_WING_RAILS}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_SAP_250LB_Bomb_Mk5_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_SAP_250LB_Bomb_Mk5_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_RIGHT_WING_RAILS}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_LEFT_WING_RAILS}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_RIGHT_WING_RAILS}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_LEFT_WING_RAILS}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_RIGHT_WING_RAILS}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_LEFT_WING_RAILS}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_MC_500LB_Bomb_Mk1_Short_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_RIGHT_WING_RAILS}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{MOSSIE_4_British_HE_60LBSAPNo2_3INCHNo1_ON_LEFT_WING_RAILS}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [11] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{British_SAP_500LB_Bomb_Mk5}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{British_SAP_500LB_Bomb_Mk5}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{British_SAP_250LB_Bomb_Mk5_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{British_SAP_250LB_Bomb_Mk5_on_Handley_Page_Type_B_Cut_Bar}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [12] = { - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "MosquitoFBMkVI", -} -return unitPayloads diff --git a/resources/customized_payloads/OH-58D.lua b/resources/customized_payloads/OH-58D.lua deleted file mode 100644 index abcf13592..000000000 --- a/resources/customized_payloads/OH-58D.lua +++ /dev/null @@ -1,87 +0,0 @@ -local unitPayloads = { - ["name"] = "OH-58D", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "oh-58-brauning", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 16, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 16, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 16, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 16, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "AGM114x2_OH_58", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 16, - }, - }, - }, - ["unitType"] = "OH-58D", -} -return unitPayloads diff --git a/resources/customized_payloads/P-47D-30.lua b/resources/customized_payloads/P-47D-30.lua deleted file mode 100644 index c94dc4cae..000000000 --- a/resources/customized_payloads/P-47D-30.lua +++ /dev/null @@ -1,166 +0,0 @@ -local unitPayloads = { - ["name"] = "P-47D-30", - ["payloads"] = { - [1] = { - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN_M65}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN_M65}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "P-47D-30", -} -return unitPayloads diff --git a/resources/customized_payloads/P-47D-30bl1.lua b/resources/customized_payloads/P-47D-30bl1.lua deleted file mode 100644 index bce0fb94b..000000000 --- a/resources/customized_payloads/P-47D-30bl1.lua +++ /dev/null @@ -1,170 +0,0 @@ -local unitPayloads = { - ["name"] = "P-47D-30bl1", - ["payloads"] = { - [1] = { - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [9] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "P-47D-30bl1", -} -return unitPayloads diff --git a/resources/customized_payloads/P-47D-40.lua b/resources/customized_payloads/P-47D-40.lua deleted file mode 100644 index 10d023d13..000000000 --- a/resources/customized_payloads/P-47D-40.lua +++ /dev/null @@ -1,292 +0,0 @@ -local unitPayloads = { - ["name"] = "P-47D-40", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN_M65}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN_M65}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [7] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [8] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - }, - ["tasks"] = { - }, - }, - [9] = { - ["displayName"] = "Liberation SEAD Escort", - ["name"] = "Liberation SEAD Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [10] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [11] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 11, - }, - }, - [12] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [13] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{P47_5_HVARS_ON_LEFT_WING_RAILS}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{P47_5_HVARS_ON_RIGHT_WING_RAILS}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "P-47D-40", -} -return unitPayloads diff --git a/resources/customized_payloads/P-51D-30-NA.lua b/resources/customized_payloads/P-51D-30-NA.lua deleted file mode 100644 index 1c43a5f4a..000000000 --- a/resources/customized_payloads/P-51D-30-NA.lua +++ /dev/null @@ -1,368 +0,0 @@ -local unitPayloads = { - ["name"] = "P-51D-30-NA", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [2] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [4] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [5] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [6] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [7] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - [8] = { - ["displayName"] = "Liberation TARCAP", - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [9] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [10] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [11] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 30, - }, - }, - }, - ["unitType"] = "P-51D-30-NA", -} -return unitPayloads diff --git a/resources/customized_payloads/P-51D.lua b/resources/customized_payloads/P-51D.lua deleted file mode 100644 index 2a7481f4c..000000000 --- a/resources/customized_payloads/P-51D.lua +++ /dev/null @@ -1,374 +0,0 @@ -local unitPayloads = { - ["name"] = "P-51D", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [2] = { - ["name"] = "Liberation TARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["displayName"] = "Liberation BARCAP", - ["name"] = "Liberation BARCAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["displayName"] = "Liberation Escort", - ["name"] = "Liberation Escort", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["displayName"] = "Liberation Fighter Sweep", - ["name"] = "Liberation Fighter Sweep", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [6] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [7] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [8] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [9] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [10] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HVAR}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{HVAR}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{HVAR}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{HVAR}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{HVAR}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{HVAR}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{HVAR}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{HVAR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{HVAR}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{HVAR}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - [11] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{AN-M64}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - [2] = 32, - [3] = 34, - [4] = 30, - }, - }, - }, - ["unitType"] = "P-51D", -} -return unitPayloads diff --git a/resources/customized_payloads/RQ-1A Predator.lua b/resources/customized_payloads/RQ-1A Predator.lua deleted file mode 100644 index 71efb9d86..000000000 --- a/resources/customized_payloads/RQ-1A Predator.lua +++ /dev/null @@ -1,23 +0,0 @@ -local unitPayloads = { - ["name"] = "RQ-1A Predator", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{ee368869-c35a-486a-afe7-284beb7c5d52}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{ee368869-c35a-486a-afe7-284beb7c5d52}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 17, - }, - }, - }, - ["unitType"] = "RQ-1A Predator", -} -return unitPayloads diff --git a/resources/customized_payloads/Rafale_A_S.lua b/resources/customized_payloads/Rafale_A_S.lua deleted file mode 100644 index 42f3abfdc..000000000 --- a/resources/customized_payloads/Rafale_A_S.lua +++ /dev/null @@ -1,225 +0,0 @@ -local unitPayloads = { - ["name"] = "Rafale_A_S", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{PTB-1500}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{Thales_RBE2}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{Exocet}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{PTB-1500}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{SCALP}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{SCALP}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [10] = { - ["CLSID"] = "{PTB-1500}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Rafale_A_S", -} -return unitPayloads diff --git a/resources/customized_payloads/Rafale_B.lua b/resources/customized_payloads/Rafale_B.lua deleted file mode 100644 index f663618ef..000000000 --- a/resources/customized_payloads/Rafale_B.lua +++ /dev/null @@ -1,265 +0,0 @@ -local unitPayloads = { - ["name"] = "Rafale_B", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{Exocet}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{SCALP}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{AS_30L}", - ["num"] = 9, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [6] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{GBU_49}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Rafale_B", -} -return unitPayloads diff --git a/resources/customized_payloads/Rafale_M.lua b/resources/customized_payloads/Rafale_M.lua deleted file mode 100644 index d0aaa5dc2..000000000 --- a/resources/customized_payloads/Rafale_M.lua +++ /dev/null @@ -1,293 +0,0 @@ -local unitPayloads = { - ["name"] = "Rafale_M", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "LAU3_HE5", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "LAU3_WP156", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "LAU3_WP156", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{D5D51E24-348C-4702-96AF-97A714E72697}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{18617C93-78E7-4359-A8CE-D754103EDF63}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [6] = { - ["name"] = "BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FC23864E-3B80-48E3-9C03-4DA8B1D7497B}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 8, - }, - [6] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 6, - }, - [8] = { - ["CLSID"] = "{RAFALE_MBDA_METEOR}", - ["num"] = 5, - }, - [9] = { - ["CLSID"] = "{0DA03783-61E4-40B2-8FAE-6AEE0A5C5AAE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{DAMOCLES}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Rafale_M", -} -return unitPayloads diff --git a/resources/customized_payloads/S-3B.lua b/resources/customized_payloads/S-3B.lua deleted file mode 100644 index e560e3dd7..000000000 --- a/resources/customized_payloads/S-3B.lua +++ /dev/null @@ -1,191 +0,0 @@ -local unitPayloads = { - ["name"] = "S-3B", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{B83CB620-5BBE-4BEA-910C-EB605A327EF9}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{B83CB620-5BBE-4BEA-910C-EB605A327EF9}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{444BA8AE-82A7-4345-842E-76154EFCCA46}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{ADD3FAE1-EBF6-4EF9-8EFC-B36B5DDF1E6B}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [6] = { - ["displayName"] = "Liberation OCA/Runway", - ["name"] = "Liberation OCA/Runway", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [7] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [2] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "S-3B", -} -return unitPayloads diff --git a/resources/customized_payloads/SA342L.lua b/resources/customized_payloads/SA342L.lua deleted file mode 100644 index d5962df26..000000000 --- a/resources/customized_payloads/SA342L.lua +++ /dev/null @@ -1,109 +0,0 @@ -local unitPayloads = { - ["name"] = "SA342L", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU_SNEB68G}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU_SNEB68G}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU_SNEB68G}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU_SNEB68G}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU_SNEB68G}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SA342L", -} -return unitPayloads diff --git a/resources/customized_payloads/SA342M.lua b/resources/customized_payloads/SA342M.lua deleted file mode 100644 index f0b92cd9d..000000000 --- a/resources/customized_payloads/SA342M.lua +++ /dev/null @@ -1,129 +0,0 @@ -local unitPayloads = { - ["name"] = "SA342M", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HOT3_R2_M}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{HOT3_L2_M}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HOT3_R2_M}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{HOT3_L2_M}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HOT3_R2_M}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{HOT3_L2_M}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HOT3_R2_M}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{HOT3_L2_M}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{HOT3_R2_M}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{HOT3_L2_M}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FAS}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SA342M", -} -return unitPayloads diff --git a/resources/customized_payloads/SA342Minigun.lua b/resources/customized_payloads/SA342Minigun.lua deleted file mode 100644 index 47d7bddc7..000000000 --- a/resources/customized_payloads/SA342Minigun.lua +++ /dev/null @@ -1,34 +0,0 @@ -local unitPayloads = { - ["name"] = "SA342Minigun", - ["payloads"] = { - [1] = { - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SA342Minigun", -} -return unitPayloads diff --git a/resources/customized_payloads/SA342Mistral.lua b/resources/customized_payloads/SA342Mistral.lua deleted file mode 100644 index 0dea18b76..000000000 --- a/resources/customized_payloads/SA342Mistral.lua +++ /dev/null @@ -1,169 +0,0 @@ -local unitPayloads = { - ["name"] = "SA342Mistral", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FAS}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 18, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FAS}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 18, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FAS}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 18, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FAS}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 18, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{MBDA_MistralD}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{MBDA_MistralG}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{FAS}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{IR_Deflector}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 18, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SA342Mistral", -} -return unitPayloads diff --git a/resources/customized_payloads/SH-60B.lua b/resources/customized_payloads/SH-60B.lua deleted file mode 100644 index 6af4a9564..000000000 --- a/resources/customized_payloads/SH-60B.lua +++ /dev/null @@ -1,19 +0,0 @@ -local unitPayloads = { - ["name"] = "SH-60B", - ["payloads"] = { - [1] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{7B8DCEB4-820B-4015-9B48-1028A4195692}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "SH-60B", -} -return unitPayloads diff --git a/resources/customized_payloads/SpitfireLFMkIX.lua b/resources/customized_payloads/SpitfireLFMkIX.lua deleted file mode 100644 index 911e29910..000000000 --- a/resources/customized_payloads/SpitfireLFMkIX.lua +++ /dev/null @@ -1,77 +0,0 @@ -local unitPayloads = { - ["name"] = "SpitfireLFMkIX", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SpitfireLFMkIX", -} -return unitPayloads diff --git a/resources/customized_payloads/SpitfireLFMkIXCW.lua b/resources/customized_payloads/SpitfireLFMkIXCW.lua deleted file mode 100644 index 91cbda7f0..000000000 --- a/resources/customized_payloads/SpitfireLFMkIXCW.lua +++ /dev/null @@ -1,77 +0,0 @@ -local unitPayloads = { - ["name"] = "SpitfireLFMkIXCW", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - }, - ["tasks"] = { - [1] = 31, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_RH_Spitfire_Wing_Carrier", - ["num"] = 3, - }, - [2] = { - ["CLSID"] = "British_GP_250LBS_Bomb_MK4_on_LH_Spitfire_Wing_Carrier", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "British_GP_500LBS_Bomb_MK4_on_British_UniversalBC_MK3", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "SpitfireLFMkIXCW", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-17M4.lua b/resources/customized_payloads/Su-17M4.lua deleted file mode 100644 index 5e889f1c2..000000000 --- a/resources/customized_payloads/Su-17M4.lua +++ /dev/null @@ -1,182 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-17M4", - ["payloads"] = { - [1] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [3] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{A5BAEAB7-6FAF-4236-AF72-0FD900F493F9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{292960BB-6518-41AC-BADA-210D65D5073C}", - ["num"] = 8, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - }, - ["unitType"] = "Su-17M4", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-24M.lua b/resources/customized_payloads/Su-24M.lua deleted file mode 100644 index 0c11a7026..000000000 --- a/resources/customized_payloads/Su-24M.lua +++ /dev/null @@ -1,154 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-24M", - ["payloads"] = { - [1] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}", - ["num"] = 2, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{KAB_1500LG_LOADOUT}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{KAB_1500LG_LOADOUT}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{E2C426E3-8B10-4E09-B733-9CDC26520F48}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{275A2855-4A79-4B2D-B082-91EA2ADF4691}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{7D7EC917-05F6-49D4-8045-61FC587DD019}", - ["num"] = 2, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}", - ["num"] = 1, - }, - [4] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 2, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 8, - }, - [2] = { - ["CLSID"] = "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - }, - ["tasks"] = { - }, - }, - }, - ["unitType"] = "Su-24M", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-25.lua b/resources/customized_payloads/Su-25.lua deleted file mode 100644 index c0dad4286..000000000 --- a/resources/customized_payloads/Su-25.lua +++ /dev/null @@ -1,222 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-25", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 6, - }, - [4] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{79D73885-0801-45a9-917F-C90FE1CE3DFC}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "Su-25", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-25T.lua b/resources/customized_payloads/Su-25T.lua deleted file mode 100644 index f4427e0b2..000000000 --- a/resources/customized_payloads/Su-25T.lua +++ /dev/null @@ -1,241 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-25T", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "{682A481F-0CB5-4693-A382-D00DD4A156D7}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{E8D4652F-FD48-45B7-BA5B-2AE05BB5A9CF}", - ["num"] = 5, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82C}", - ["num"] = 11, - }, - [2] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82D}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{0180F983-C14A-11d8-9897-000476191836}", - ["num"] = 10, - }, - [5] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{F789E86A-EE2E-4E6B-B81E-D5E5F903B6ED}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{F789E86A-EE2E-4E6B-B81E-D5E5F903B6ED}", - ["num"] = 4, - }, - [9] = { - ["CLSID"] = "{B1EF6B0E-3D91-4047-A7A5-A99E7D8B4A8B}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 9, - }, - [11] = { - ["CLSID"] = "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}", - ["num"] = 3, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82D}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{4203753F-8198-4E85-9924-6F8FF679F9FF}", - ["num"] = 10, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82C}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82D}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B5CA9846-776E-4230-B4FD-8BCC9BFB1676}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B5CA9846-776E-4230-B4FD-8BCC9BFB1676}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82C}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82D}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{601C99F7-9AF3-4ed7-A565-F8B8EC0D7AAC}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{0519A264-0AB6-11d6-9193-00A0249B6F00}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{601C99F7-9AF3-4ed7-A565-F8B8EC0D7AAC}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{CBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82C}", - ["num"] = 11, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - }, - ["unitType"] = "Su-25T", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-27.lua b/resources/customized_payloads/Su-27.lua deleted file mode 100644 index 15090ed58..000000000 --- a/resources/customized_payloads/Su-27.lua +++ /dev/null @@ -1,250 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-27", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 10, - [4] = 11, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [3] = { - ["CLSID"] = "{TWIN_B13L_5OF}", - ["num"] = 8, - }, - [4] = { - ["CLSID"] = "{F99BEC1A-869D-4AC7-9730-FBA0E3B1F5FC}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{F99BEC1A-869D-4AC7-9730-FBA0E3B1F5FC}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{TWIN_B13L_5OF}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "Su-27", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-30.lua b/resources/customized_payloads/Su-30.lua deleted file mode 100644 index 4c3c91c08..000000000 --- a/resources/customized_payloads/Su-30.lua +++ /dev/null @@ -1,250 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-30", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 11, - [3] = 10, - [4] = 19, - }, - }, - [2] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{2234F529-1D57-4496-8BB0-0150F9BDBBD2}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{2234F529-1D57-4496-8BB0-0150F9BDBBD2}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "Su-30", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-33.lua b/resources/customized_payloads/Su-33.lua deleted file mode 100644 index fa1d885c2..000000000 --- a/resources/customized_payloads/Su-33.lua +++ /dev/null @@ -1,274 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-33", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{37DCC01E-9E02-432F-B61D-10C166CA2798}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{FC56DF80-9B09-44C5-8976-DCFAFF219062}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 9, - }, - [5] = { - ["CLSID"] = "{A0648264-4BC0-4EE8-A543-D119F6BA4257}", - ["num"] = 4, - }, - [6] = { - ["CLSID"] = "{TWIN_S25}", - ["num"] = 3, - }, - [7] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [8] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{E8069896-8435-4B90-95C0-01A03AE6E400}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 19, - [2] = 18, - [3] = 11, - [4] = 10, - }, - }, - }, - ["unitType"] = "Su-33", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-34.lua b/resources/customized_payloads/Su-34.lua deleted file mode 100644 index 6e6b53493..000000000 --- a/resources/customized_payloads/Su-34.lua +++ /dev/null @@ -1,271 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-34", - ["payloads"] = { - [1] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{X-31A}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{X-31A}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{X-31A}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{X-31A}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{X-31A}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{X-31A}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{X-25MPU}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{X-25MPU}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{X-25MPU}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{X-25MPU}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [3] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{X-25MR}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{X-25MR}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{X-25MR}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{X-25MR}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 7, - }, - [8] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 9, - }, - [10] = { - ["CLSID"] = "{D5435F26-F120-4FA3-9867-34ACE562EF1B}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [12] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 31, - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82F}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{44EE8698-89F9-48EE-AF36-5FD31896A82A}", - ["num"] = 12, - }, - [11] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 7, - }, - [12] = { - ["CLSID"] = "{9B25D316-0434-4954-868F-D51DB1A38DF0}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - }, - ["unitType"] = "Su-34", -} -return unitPayloads diff --git a/resources/customized_payloads/Su-57.lua b/resources/customized_payloads/Su-57.lua deleted file mode 100644 index fd4f7479d..000000000 --- a/resources/customized_payloads/Su-57.lua +++ /dev/null @@ -1,289 +0,0 @@ -local unitPayloads = { - ["name"] = "Su-57", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 11, - }, - [4] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 5, - }, - [9] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 4, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 3, - }, - [11] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 9, - }, - [12] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{40AB87E8-BEFB-4D85-90D9-B2753ACF9514}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{40AB87E8-BEFB-4D85-90D9-B2753ACF9514}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{40AB87E8-BEFB-4D85-90D9-B2753ACF9514}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{40AB87E8-BEFB-4D85-90D9-B2753ACF9514}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 6, - }, - [11] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 7, - }, - [12] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 6, - }, - [11] = { - ["CLSID"] = "{KH_59MK2}", - ["num"] = 7, - }, - [12] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{B4FC81C9-B861-4E87-BBDC-A1158E648EBF}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{B4FC81C9-B861-4E87-BBDC-A1158E648EBF}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{F72F47E5-C83A-4B85-96ED-D3E46671EE9A}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 6, - }, - [11] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 7, - }, - [12] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{3C612111-C7AD-476E-8A8E-2485812F4E5C}", - ["num"] = 11, - }, - [6] = { - ["CLSID"] = "{53BE25A4-C86C-4571-9BC0-47D668349595}", - ["num"] = 9, - }, - [7] = { - ["CLSID"] = "{53BE25A4-C86C-4571-9BC0-47D668349595}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 5, - }, - [10] = { - ["CLSID"] = "{FBC29BFE-3D24-4C64-B81D-941239D12249}", - ["num"] = 10, - }, - [11] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 7, - }, - [12] = { - ["CLSID"] = "{RVV-AE}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "Su-57", -} -return unitPayloads diff --git a/resources/customized_payloads/Tornado GR4.lua b/resources/customized_payloads/Tornado GR4.lua deleted file mode 100644 index c83d1caa8..000000000 --- a/resources/customized_payloads/Tornado GR4.lua +++ /dev/null @@ -1,375 +0,0 @@ -local unitPayloads = { - ["name"] = "Tornado GR4", - ["payloads"] = { - [1] = { - ["displayName"] = "Liberation CAS", - ["name"] = "Liberation CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [2] = { - ["displayName"] = "Liberation Strike", - ["name"] = "Liberation Strike", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - [7] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [8] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [9] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [10] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [3] = { - ["displayName"] = "Liberation Anti-ship", - ["name"] = "Liberation Anti-ship", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{1461CD18-429A-42A9-A21F-4C621ECD4573}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{1461CD18-429A-42A9-A21F-4C621ECD4573}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [4] = { - ["displayName"] = "Liberation SEAD", - ["name"] = "Liberation SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["displayName"] = "Liberation DEAD", - ["name"] = "Liberation DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 7, - }, - [9] = { - ["CLSID"] = "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}", - ["num"] = 6, - }, - [10] = { - ["CLSID"] = "{A111396E-D3E8-4b9c-8AC9-2432489304D5}", - ["num"] = 5, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [6] = { - ["displayName"] = "Liberation BAI", - ["name"] = "Liberation BAI", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [7] = { - ["displayName"] = "Liberation OCA/Aircraft", - ["name"] = "Liberation OCA/Aircraft", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 6, - }, - [7] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 5, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [9] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [10] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [8] = { - ["displayName"] = "Liberation SEAD Escort", - ["name"] = "Liberation SEAD Escort", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [3] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 3, - }, - [5] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [7] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}", - ["num"] = 4, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "Tornado GR4", -} -return unitPayloads diff --git a/resources/customized_payloads/Tornado IDS.lua b/resources/customized_payloads/Tornado IDS.lua deleted file mode 100644 index 628fc2271..000000000 --- a/resources/customized_payloads/Tornado IDS.lua +++ /dev/null @@ -1,206 +0,0 @@ -local unitPayloads = { - ["name"] = "Tornado IDS", - ["payloads"] = { - [1] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 11, - }, - [8] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 29, - }, - }, - [2] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{7210496B-7B81-4B52-80D6-8529ECF847CD}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{7210496B-7B81-4B52-80D6-8529ECF847CD}", - ["num"] = 9, - }, - [6] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}", - ["num"] = 11, - }, - [8] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - [2] = { - ["CLSID"] = "{8C3F26A2-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - [5] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}", - ["num"] = 10, - }, - [9] = { - ["CLSID"] = "{EF124821-F9BB-4314-A153-E0E2FE1162C4}", - ["num"] = 11, - }, - [10] = { - ["CLSID"] = "{8C3F26A1-FA0F-11d5-9190-00A0249B6F00}", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 32, - }, - }, - }, - ["unitType"] = "Tornado IDS", -} -return unitPayloads diff --git a/resources/customized_payloads/Tu-142.lua b/resources/customized_payloads/Tu-142.lua deleted file mode 100644 index 2570bf017..000000000 --- a/resources/customized_payloads/Tu-142.lua +++ /dev/null @@ -1,67 +0,0 @@ -local unitPayloads = { - ["name"] = "Tu-142", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C42EE4C3-355C-4B83-8B22-B39430B8F4AE}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C42EE4C3-355C-4B83-8B22-B39430B8F4AE}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C42EE4C3-355C-4B83-8B22-B39430B8F4AE}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C42EE4C3-355C-4B83-8B22-B39430B8F4AE}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{C42EE4C3-355C-4B83-8B22-B39430B8F4AE}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "Tu-142", -} -return unitPayloads diff --git a/resources/customized_payloads/Tu-160.lua b/resources/customized_payloads/Tu-160.lua deleted file mode 100644 index e0506bfce..000000000 --- a/resources/customized_payloads/Tu-160.lua +++ /dev/null @@ -1,82 +0,0 @@ -local unitPayloads = { - ["name"] = "Tu-160", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [2] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - [5] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - }, - }, - }, - ["unitType"] = "Tu-160", -} -return unitPayloads diff --git a/resources/customized_payloads/Tu-22M3.lua b/resources/customized_payloads/Tu-22M3.lua deleted file mode 100644 index d64f08624..000000000 --- a/resources/customized_payloads/Tu-22M3.lua +++ /dev/null @@ -1,123 +0,0 @@ -local unitPayloads = { - ["name"] = "Tu-22M3", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [3] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 4, - }, - [3] = { - ["CLSID"] = "{AD5E5863-08FC-4283-B92C-162E2B2BD3FF}", - ["num"] = 3, - }, - [4] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 2, - }, - [5] = { - ["CLSID"] = "{E1AAE713-5FC3-4CAA-9FF5-3FDCFB899E33}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [4] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 5, - }, - [2] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{12429ECF-03F0-4DF6-BCBD-5D38B6343DE1}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 30, - }, - }, - }, - ["unitType"] = "Tu-22M3", -} -return unitPayloads diff --git a/resources/customized_payloads/Tu-95MS.lua b/resources/customized_payloads/Tu-95MS.lua deleted file mode 100644 index 433413789..000000000 --- a/resources/customized_payloads/Tu-95MS.lua +++ /dev/null @@ -1,67 +0,0 @@ -local unitPayloads = { - ["name"] = "Tu-95MS", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{0290F5DE-014A-4BB1-9843-D717749B1DED}", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 33, - }, - }, - }, - ["unitType"] = "Tu-95MS", -} -return unitPayloads diff --git a/resources/customized_payloads/UH-1H.lua b/resources/customized_payloads/UH-1H.lua deleted file mode 100644 index c38b3b507..000000000 --- a/resources/customized_payloads/UH-1H.lua +++ /dev/null @@ -1,162 +0,0 @@ -local unitPayloads = { - ["name"] = "UH-1H", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "M134_L", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "M134_R", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - [2] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "M134_L", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "M134_R", - ["num"] = 6, - }, - [3] = { - ["CLSID"] = "M60_SIDE_R", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "M60_SIDE_L", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "M134_L", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "M134_R", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - [4] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "M134_L", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "M134_R", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - [5] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "M134_L", - ["num"] = 1, - }, - [2] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 2, - }, - [3] = { - ["CLSID"] = "XM158_MK5", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "M134_R", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - [6] = { - ["displayName"] = "Liberation Air Assault", - ["name"] = "Liberation Air Assault", - ["pylons"] = { - [1] = { - ["CLSID"] = "M60_SIDE_R", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "M60_SIDE_L", - ["num"] = 3, - }, - }, - ["tasks"] = { - [1] = 32, - [2] = 31, - [3] = 35, - [4] = 16, - }, - }, - }, - ["unitType"] = "UH-1H", -} -return unitPayloads diff --git a/resources/customized_payloads/UH-60L.lua b/resources/customized_payloads/UH-60L.lua deleted file mode 100644 index 1250b68e5..000000000 --- a/resources/customized_payloads/UH-60L.lua +++ /dev/null @@ -1,50 +0,0 @@ -local unitPayloads = -{ - ["name"] = "UH-60L", - ["payloads"] = - { - [1] = - { - ["name"] = "Liberation Ferry", - ["pylons"] = - { - [1] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", - ["num"] = 7, - }, - [2] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", - ["num"] = 1, - }, - [3] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", - ["num"] = 2, - }, - [4] = { - ["CLSID"] = "{UH60_FUEL_TANK_230}", - ["num"] = 6, - }, - [5] = { - ["CLSID"] = "{UH60_SEAT_GUNNER_L}", - ["num"] = 3, - }, - [6] = { - ["CLSID"] = "{UH60_SEAT_CARGO_ALL}", - ["num"] = 4, - }, - [7] = { - ["CLSID"] = "{UH60_SEAT_GUNNER_R}", - ["num"] = 5, - }, - }, - ["tasks"] = - { - [1] = 35, - [2] = 17, - }, - }, - }, - ["tasks"] = {}, - ["unitType"] = "UH-60L", -} -return unitPayloads diff --git a/resources/customized_payloads/VSN_F104G.lua b/resources/customized_payloads/VSN_F104G.lua deleted file mode 100644 index 99e8972e7..000000000 --- a/resources/customized_payloads/VSN_F104G.lua +++ /dev/null @@ -1,166 +0,0 @@ -local unitPayloads = { - ["name"] = "VSN_F104G", - ["payloads"] = { - [1] = { - ["displayName"] = "CAP", - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 4, - }, - [2] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [3] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 8, - }, - [5] = { - ["CLSID"] = "VSN_F104G_R_PTB", - ["num"] = 10, - }, - [6] = { - ["CLSID"] = "VSN_F104G_L_PTB", - ["num"] = 2, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [2] = { - ["displayName"] = "DEAD", - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F104G_L_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "VSN_F104G_R_PTB", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [3] = { - ["displayName"] = "CAS", - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F104G_L_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "VSN_F104G_R_PTB", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [4] = { - ["displayName"] = "STRIKE", - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F104G_L_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "VSN_F104G_R_PTB", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [5] = { - ["displayName"] = "OCA", - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F104G_L_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 8, - }, - [3] = { - ["CLSID"] = "VSN_F104G_R_PTB", - ["num"] = 10, - }, - [4] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 4, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "VSN_F104G", -} -return unitPayloads diff --git a/resources/customized_payloads/VSN_F104S.lua b/resources/customized_payloads/VSN_F104S.lua deleted file mode 100644 index 49824b6c3..000000000 --- a/resources/customized_payloads/VSN_F104S.lua +++ /dev/null @@ -1,50 +0,0 @@ -local unitPayloads = { - ["name"] = "VSN_F104S", - ["payloads"] = { - [1] = { - ["displayName"] = "CAP", - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "VSN_F104G_PTB", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "VSN_F104G_PTB", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "VSN_F104S", -} -return unitPayloads diff --git a/resources/customized_payloads/VSN_F104S_AG.lua b/resources/customized_payloads/VSN_F104S_AG.lua deleted file mode 100644 index 24af0c798..000000000 --- a/resources/customized_payloads/VSN_F104S_AG.lua +++ /dev/null @@ -1,189 +0,0 @@ -local unitPayloads = { - ["name"] = "VSN_F104S_AG", - ["payloads"] = { - [1] = { - ["displayName"] = "DEAD", - ["name"] = "DEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [2] = { - ["displayName"] = "CAS", - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{08164777-5E9C-4B08-B48E-5AA7AFB246E2}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [3] = { - ["displayName"] = "STRIKE", - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - [4] = { - ["displayName"] = "OCA", - ["name"] = "OCA", - ["pylons"] = { - [1] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 6, - }, - [6] = { - ["CLSID"] = "{AIM-9L}", - ["num"] = 7, - }, - [7] = { - ["CLSID"] = "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}", - ["num"] = 8, - }, - [8] = { - ["CLSID"] = "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}", - ["num"] = 9, - }, - [9] = { - ["CLSID"] = "{LAU-138 wtip - AIM-9L}", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 19, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "VSN_F104S_AG", -} -return unitPayloads diff --git a/resources/customized_payloads/VSN_F4B.lua b/resources/customized_payloads/VSN_F4B.lua deleted file mode 100644 index 3d0c251bb..000000000 --- a/resources/customized_payloads/VSN_F4B.lua +++ /dev/null @@ -1,264 +0,0 @@ -local unitPayloads = { - ["name"] = "VSN_F4B", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F4EL_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9L", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "LAU-105_2*AIM-9L", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "VSN_F4ER_PTB", - ["num"] = 10, - }, - [9] ={ - ["CLSID"] = "", - ["num"] = 11, - }, - [10] ={ - ["CLSID"] = "", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - [10] ={ - ["CLSID"] = "", - ["num"] = 11, - }, - [11] ={ - ["CLSID"] = "", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - [10] ={ - ["CLSID"] = "", - ["num"] = 11, - }, - [11] ={ - ["CLSID"] = "", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - [10] ={ - ["CLSID"] = "", - ["num"] = 11, - }, - [11] ={ - ["CLSID"] = "", - ["num"] = 12, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - [10] ={ - ["CLSID"] = "", - ["num"] = 11, - }, - [11] ={ - ["CLSID"] = "", - ["num"] = 12, - }, - }, ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "VSN_F4B", -} -return unitPayloads diff --git a/resources/customized_payloads/VSN_F4C.lua b/resources/customized_payloads/VSN_F4C.lua deleted file mode 100644 index c853b18a6..000000000 --- a/resources/customized_payloads/VSN_F4C.lua +++ /dev/null @@ -1,224 +0,0 @@ -local unitPayloads = { - ["name"] = "VSN_F4C", - ["payloads"] = { - [1] = { - ["name"] = "CAP", - ["pylons"] = { - [1] = { - ["CLSID"] = "VSN_F4EL_PTB", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "LAU-105_2*AIM-9L", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [5] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [6] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [7] = { - ["CLSID"] = "LAU-105_2*AIM-9L", - ["num"] = 9, - }, - [8] = { - ["CLSID"] = "VSN_F4ER_PTB", - ["num"] = 10, - }, - }, - ["tasks"] = { - [1] = 18, - [2] = 19, - [3] = 11, - }, - }, - [2] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [3] = { - ["name"] = "SEAD", - ["pylons"] = { - [1] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{3E6B632D-65EB-44D2-9501-1C2D04515404}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "VSN_F4EL_PTB", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "VSN_F4ER_PTB", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [4] = { - ["name"] = "STRIKE", - ["pylons"] = { - [1] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - }, - ["tasks"] = { - [1] = 11, - }, - }, - [5] = { - ["name"] = "ANTISHIP", - ["pylons"] = { - [1] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 9, - }, - [2] = { - ["CLSID"] = "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}", - ["num"] = 3, - }, - [3] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 5, - }, - [4] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 7, - }, - [5] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 2, - }, - [6] = { - ["CLSID"] = "{F3EFE0AB-E91A-42D8-9CA2-B63C91ED570A}", - ["num"] = 10, - }, - [7] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 4, - }, - [8] = { - ["CLSID"] = "{AIM-7F}", - ["num"] = 8, - }, - [9] = { - ["CLSID"] = "VSN_F4EC_PTB", - ["num"] = 6, - }, - }, ["tasks"] = { - [1] = 11, - }, - }, - }, - ["unitType"] = "VSN_F4C", -} -return unitPayloads diff --git a/resources/customized_payloads/WingLoong-I.lua b/resources/customized_payloads/WingLoong-I.lua deleted file mode 100644 index aa1a019ac..000000000 --- a/resources/customized_payloads/WingLoong-I.lua +++ /dev/null @@ -1,25 +0,0 @@ -local unitPayloads = { - ["name"] = "WingLoong-I", - ["payloads"] = { - [1] = { - ["name"] = "CAS", - ["pylons"] = { - [1] = { - ["CLSID"] = "DIS_AKD-10", - ["num"] = 2, - }, - [2] = { - ["CLSID"] = "DIS_AKD-10", - ["num"] = 1, - }, - }, - ["tasks"] = { - [1] = 17, - }, - }, - }, - ["tasks"] = { - }, - ["unitType"] = "WingLoong-I", -} -return unitPayloads diff --git a/resources/dcs/beacons/caucasus.json b/resources/dcs/beacons/caucasus.json deleted file mode 100644 index ba758ed5b..000000000 --- a/resources/dcs/beacons/caucasus.json +++ /dev/null @@ -1,1150 +0,0 @@ -{ - "airfield12_0": { - "name": "Anapa-Vityazevo", - "callsign": "AP", - "beacon_type": 11, - "hertz": 443000, - "channel": null - }, - "airfield12_1": { - "name": "Anapa-Vityazevo", - "callsign": "P", - "beacon_type": 12, - "hertz": 215000, - "channel": null - }, - "airfield12_2": { - "name": "Anapa-Vityazevo", - "callsign": "AN", - "beacon_type": 11, - "hertz": 443000, - "channel": null - }, - "airfield12_3": { - "name": "Anapa-Vityazevo", - "callsign": "N", - "beacon_type": 12, - "hertz": 215000, - "channel": null - }, - "airfield22_0": { - "name": "Batumi", - "callsign": "ILU", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield22_1": { - "name": "Batumi", - "callsign": "ILU", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield22_2": { - "name": "Batumi", - "callsign": "BTM", - "beacon_type": 4, - "hertz": 977000000, - "channel": 16 - }, - "airfield22_3": { - "name": "Batumi", - "callsign": "LU", - "beacon_type": 9, - "hertz": 430000, - "channel": null - }, - "airfield32_0": { - "name": "Beslan", - "callsign": "CX", - "beacon_type": 11, - "hertz": 1050000, - "channel": null - }, - "airfield32_1": { - "name": "Beslan", - "callsign": "C", - "beacon_type": 12, - "hertz": 250000, - "channel": null - }, - "airfield32_2": { - "name": "Beslan", - "callsign": "ICH", - "beacon_type": 13, - "hertz": 110500000, - "channel": null - }, - "airfield32_3": { - "name": "Beslan", - "callsign": "ICH", - "beacon_type": 14, - "hertz": 110500000, - "channel": null - }, - "airfield17_0": { - "name": "Gelendzhik", - "callsign": "GN", - "beacon_type": 9, - "hertz": 1000000, - "channel": null - }, - "airfield17_1": { - "name": "Gelendzhik", - "callsign": "GN", - "beacon_type": 1, - "hertz": 114300000, - "channel": 90 - }, - "airfield21_0": { - "name": "Gudauta", - "callsign": "XC", - "beacon_type": 10, - "hertz": 395000, - "channel": null - }, - "airfield24_0": { - "name": "Kobuleti", - "callsign": "KT", - "beacon_type": 11, - "hertz": 870000, - "channel": null - }, - "airfield24_1": { - "name": "Kobuleti", - "callsign": "T", - "beacon_type": 12, - "hertz": 490000, - "channel": null - }, - "airfield24_2": { - "name": "Kobuleti", - "callsign": "IKB", - "beacon_type": 13, - "hertz": 111500000, - "channel": null - }, - "airfield24_3": { - "name": "Kobuleti", - "callsign": "IKB", - "beacon_type": 14, - "hertz": 111500000, - "channel": null - }, - "airfield24_4": { - "name": "Kobuleti", - "callsign": "KBL", - "beacon_type": 4, - "hertz": 1154000000, - "channel": 67 - }, - "airfield13_0": { - "name": "Krasnodar-Center", - "callsign": "OC", - "beacon_type": 11, - "hertz": 625000, - "channel": null - }, - "airfield13_1": { - "name": "Krasnodar-Center", - "callsign": "O", - "beacon_type": 12, - "hertz": 303000, - "channel": null - }, - "airfield13_2": { - "name": "Krasnodar-Center", - "callsign": "MB", - "beacon_type": 11, - "hertz": 625000, - "channel": null - }, - "airfield13_3": { - "name": "Krasnodar-Center", - "callsign": "M", - "beacon_type": 12, - "hertz": 303000, - "channel": null - }, - "airfield13_4": { - "name": "Krasnodar-Center", - "callsign": "MB", - "beacon_type": 15, - "hertz": 838000000, - "channel": 38 - }, - "airfield13_5": { - "name": "Krasnodar-Center", - "callsign": "MB", - "beacon_type": 16, - "hertz": 838000000, - "channel": 38 - }, - "airfield13_6": { - "name": "Krasnodar-Center", - "callsign": "MB", - "beacon_type": 6, - "hertz": 840000000, - "channel": 40 - }, - "airfield19_0": { - "name": "Krasnodar-Pashkovsky", - "callsign": "KR", - "beacon_type": 11, - "hertz": 493000, - "channel": null - }, - "airfield19_1": { - "name": "Krasnodar-Pashkovsky", - "callsign": "K", - "beacon_type": 12, - "hertz": 240000, - "channel": null - }, - "airfield19_2": { - "name": "Krasnodar-Pashkovsky", - "callsign": "LD", - "beacon_type": 11, - "hertz": 493000, - "channel": null - }, - "airfield19_3": { - "name": "Krasnodar-Pashkovsky", - "callsign": "L", - "beacon_type": 12, - "hertz": 240000, - "channel": null - }, - "airfield19_4": { - "name": "Krasnodar-Pashkovsky", - "callsign": "KN", - "beacon_type": 1, - "hertz": 115800000, - "channel": 105 - }, - "airfield15_0": { - "name": "Krymsk", - "callsign": "KW", - "beacon_type": 11, - "hertz": 408000, - "channel": null - }, - "airfield15_1": { - "name": "Krymsk", - "callsign": "K", - "beacon_type": 12, - "hertz": 803000, - "channel": null - }, - "airfield15_2": { - "name": "Krymsk", - "callsign": "OX", - "beacon_type": 11, - "hertz": 408000, - "channel": null - }, - "airfield15_3": { - "name": "Krymsk", - "callsign": "O", - "beacon_type": 12, - "hertz": 803000, - "channel": null - }, - "airfield15_4": { - "name": "Krymsk", - "callsign": "OX", - "beacon_type": 16, - "hertz": 826000000, - "channel": null - }, - "airfield15_5": { - "name": "Krymsk", - "callsign": "KW", - "beacon_type": 16, - "hertz": 826000000, - "channel": null - }, - "airfield15_6": { - "name": "Krymsk", - "callsign": "KW", - "beacon_type": 15, - "hertz": 826000000, - "channel": 26 - }, - "airfield15_7": { - "name": "Krymsk", - "callsign": "OX", - "beacon_type": 15, - "hertz": 826000000, - "channel": 26 - }, - "airfield15_8": { - "name": "Krymsk", - "callsign": "KW", - "beacon_type": 6, - "hertz": 828000000, - "channel": 28 - }, - "airfield25_0": { - "name": "Kutaisi", - "callsign": "IKS", - "beacon_type": 13, - "hertz": 109750000, - "channel": null - }, - "airfield25_1": { - "name": "Kutaisi", - "callsign": "IKS", - "beacon_type": 14, - "hertz": 109750000, - "channel": null - }, - "airfield25_2": { - "name": "Kutaisi", - "callsign": "TI", - "beacon_type": 10, - "hertz": 477000, - "channel": null - }, - "airfield25_3": { - "name": "Kutaisi", - "callsign": "KTS", - "beacon_type": 4, - "hertz": 1005000000, - "channel": 44 - }, - "airfield25_4": { - "name": "Kutaisi", - "callsign": "KT", - "beacon_type": 1, - "hertz": 113600000, - "channel": 83 - }, - "airfield29_0": { - "name": "Tbilisi-Lochini", - "callsign": "BP", - "beacon_type": 11, - "hertz": 342000, - "channel": null - }, - "airfield29_1": { - "name": "Tbilisi-Lochini", - "callsign": "B", - "beacon_type": 12, - "hertz": 923000, - "channel": null - }, - "airfield29_2": { - "name": "Tbilisi-Lochini", - "callsign": "IVP", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield29_3": { - "name": "Tbilisi-Lochini", - "callsign": "IVP", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield29_4": { - "name": "Tbilisi-Lochini", - "callsign": "NA", - "beacon_type": 11, - "hertz": 211000, - "channel": null - }, - "airfield29_5": { - "name": "Tbilisi-Lochini", - "callsign": "N", - "beacon_type": 12, - "hertz": 435000, - "channel": null - }, - "airfield29_6": { - "name": "Tbilisi-Lochini", - "callsign": "INA", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield29_7": { - "name": "Tbilisi-Lochini", - "callsign": "INA", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield29_8": { - "name": "Tbilisi-Lochini", - "callsign": "TB", - "beacon_type": 1, - "hertz": 113700000, - "channel": 84 - }, - "airfield29_9": { - "name": "Tbilisi-Lochini", - "callsign": "GTB", - "beacon_type": 4, - "hertz": 986000000, - "channel": 25 - }, - "airfield16_0": { - "name": "Maykop-Khanskaya", - "callsign": "RK", - "beacon_type": 11, - "hertz": 289000, - "channel": null - }, - "airfield16_1": { - "name": "Maykop-Khanskaya", - "callsign": "R", - "beacon_type": 12, - "hertz": 591000, - "channel": null - }, - "airfield16_2": { - "name": "Maykop-Khanskaya", - "callsign": "DG", - "beacon_type": 11, - "hertz": 289000, - "channel": null - }, - "airfield16_3": { - "name": "Maykop-Khanskaya", - "callsign": "D", - "beacon_type": 12, - "hertz": 591000, - "channel": null - }, - "airfield16_4": { - "name": "Maykop-Khanskaya", - "callsign": "DG", - "beacon_type": 15, - "hertz": 836000000, - "channel": 36 - }, - "airfield16_5": { - "name": "Maykop-Khanskaya", - "callsign": "DG", - "beacon_type": 16, - "hertz": 836000000, - "channel": 36 - }, - "airfield16_6": { - "name": "Maykop-Khanskaya", - "callsign": "DG", - "beacon_type": 6, - "hertz": 834000000, - "channel": 34 - }, - "airfield26_0": { - "name": "MineralnyeVody", - "callsign": "NR", - "beacon_type": 11, - "hertz": 583000, - "channel": null - }, - "airfield26_1": { - "name": "MineralnyeVody", - "callsign": "N", - "beacon_type": 12, - "hertz": 283000, - "channel": null - }, - "airfield26_2": { - "name": "MineralnyeVody", - "callsign": "IMW", - "beacon_type": 13, - "hertz": 109300000, - "channel": null - }, - "airfield26_3": { - "name": "MineralnyeVody", - "callsign": "IMW", - "beacon_type": 14, - "hertz": 109300000, - "channel": null - }, - "airfield26_4": { - "name": "MineralnyeVody", - "callsign": "MD", - "beacon_type": 11, - "hertz": 583000, - "channel": null - }, - "airfield26_5": { - "name": "MineralnyeVody", - "callsign": "D", - "beacon_type": 12, - "hertz": 283000, - "channel": null - }, - "airfield26_6": { - "name": "MineralnyeVody", - "callsign": "IMD", - "beacon_type": 13, - "hertz": 111700000, - "channel": null - }, - "airfield26_7": { - "name": "MineralnyeVody", - "callsign": "IMD", - "beacon_type": 14, - "hertz": 111700000, - "channel": null - }, - "airfield26_8": { - "name": "MineralnyeVody", - "callsign": "MN", - "beacon_type": 1, - "hertz": 117100000, - "channel": 118 - }, - "airfield28_0": { - "name": "Mozdok", - "callsign": "DO", - "beacon_type": 11, - "hertz": 525000, - "channel": null - }, - "airfield28_1": { - "name": "Mozdok", - "callsign": "D", - "beacon_type": 12, - "hertz": 1065000, - "channel": null - }, - "airfield28_2": { - "name": "Mozdok", - "callsign": "RM", - "beacon_type": 11, - "hertz": 525000, - "channel": null - }, - "airfield28_3": { - "name": "Mozdok", - "callsign": "R", - "beacon_type": 12, - "hertz": 1065000, - "channel": null - }, - "airfield28_4": { - "name": "Mozdok", - "callsign": "MZ", - "beacon_type": 15, - "hertz": 822000000, - "channel": 22 - }, - "airfield28_5": { - "name": "Mozdok", - "callsign": "MZ", - "beacon_type": 16, - "hertz": 822000000, - "channel": 22 - }, - "airfield28_6": { - "name": "Mozdok", - "callsign": "MK", - "beacon_type": 15, - "hertz": 822000000, - "channel": 22 - }, - "airfield28_7": { - "name": "Mozdok", - "callsign": "MK", - "beacon_type": 16, - "hertz": 822000000, - "channel": 22 - }, - "airfield28_8": { - "name": "Mozdok", - "callsign": "MZ", - "beacon_type": 6, - "hertz": 820000000, - "channel": 20 - }, - "airfield27_0": { - "name": "Nalchik", - "callsign": "NL", - "beacon_type": 11, - "hertz": 718000, - "channel": null - }, - "airfield27_1": { - "name": "Nalchik", - "callsign": "N", - "beacon_type": 12, - "hertz": 350000, - "channel": null - }, - "airfield27_2": { - "name": "Nalchik", - "callsign": "INL", - "beacon_type": 13, - "hertz": 110500000, - "channel": null - }, - "airfield27_3": { - "name": "Nalchik", - "callsign": "INL", - "beacon_type": 14, - "hertz": 110500000, - "channel": null - }, - "airfield23_0": { - "name": "Senaki-Kolkhi", - "callsign": "BI", - "beacon_type": 11, - "hertz": 335000, - "channel": null - }, - "airfield23_1": { - "name": "Senaki-Kolkhi", - "callsign": "B", - "beacon_type": 12, - "hertz": 688000, - "channel": null - }, - "airfield23_2": { - "name": "Senaki-Kolkhi", - "callsign": "ITS", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield23_3": { - "name": "Senaki-Kolkhi", - "callsign": "ITS", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield23_4": { - "name": "Senaki-Kolkhi", - "callsign": "TSK", - "beacon_type": 4, - "hertz": 992000000, - "channel": 31 - }, - "airfield18_0": { - "name": "Sochi-Adler", - "callsign": "CO", - "beacon_type": 10, - "hertz": 761000, - "channel": null - }, - "airfield18_1": { - "name": "Sochi-Adler", - "callsign": "ISO", - "beacon_type": 13, - "hertz": 111100000, - "channel": null - }, - "airfield18_2": { - "name": "Sochi-Adler", - "callsign": "ISO", - "beacon_type": 14, - "hertz": 111100000, - "channel": null - }, - "airfield20_0": { - "name": "Sukhumi-Babushara", - "callsign": "AV", - "beacon_type": 11, - "hertz": 489000, - "channel": null - }, - "airfield20_1": { - "name": "Sukhumi-Babushara", - "callsign": "A", - "beacon_type": 12, - "hertz": 995000, - "channel": null - }, - "airfield31_0": { - "name": "Vaziani", - "callsign": "IVZ", - "beacon_type": 13, - "hertz": 108750000, - "channel": null - }, - "airfield31_1": { - "name": "Vaziani", - "callsign": "IVZ", - "beacon_type": 14, - "hertz": 108750000, - "channel": null - }, - "airfield31_2": { - "name": "Vaziani", - "callsign": "IVI", - "beacon_type": 13, - "hertz": 108750000, - "channel": null - }, - "airfield31_3": { - "name": "Vaziani", - "callsign": "IVI", - "beacon_type": 14, - "hertz": 108750000, - "channel": null - }, - "airfield31_4": { - "name": "Vaziani", - "callsign": "VAS", - "beacon_type": 4, - "hertz": 983000000, - "channel": 22 - }, - "world_0": { - "name": "Ust-Labinks", - "callsign": "NZ", - "beacon_type": 8, - "hertz": 330000, - "channel": null - }, - "world_1": { - "name": "Chervonoglinskoye", - "callsign": "AR", - "beacon_type": 8, - "hertz": 440000, - "channel": null - }, - "world_2": { - "name": "Dmitrovka", - "callsign": "DM", - "beacon_type": 8, - "hertz": 690000, - "channel": null - }, - "world_3": { - "name": "Agoy", - "callsign": "AG", - "beacon_type": 8, - "hertz": 381000, - "channel": null - }, - "world_4": { - "name": "Maykop", - "callsign": "MA", - "beacon_type": 8, - "hertz": 682000, - "channel": null - }, - "world_5": { - "name": "Herson", - "callsign": "HS", - "beacon_type": 8, - "hertz": 1065000, - "channel": null - }, - "world_6": { - "name": "Smolenkaya", - "callsign": "SM", - "beacon_type": 8, - "hertz": 662000, - "channel": null - }, - "world_7": { - "name": "Kislovodsk", - "callsign": "KW", - "beacon_type": 8, - "hertz": 995000, - "channel": null - }, - "world_8": { - "name": "Taganrog", - "callsign": "TC", - "beacon_type": 8, - "hertz": 470000, - "channel": null - }, - "world_9": { - "name": "Feodosiya", - "callsign": "IL", - "beacon_type": 8, - "hertz": 300500, - "channel": null - }, - "world_10": { - "name": "Shyriaeve", - "callsign": "SH", - "beacon_type": 8, - "hertz": 389000, - "channel": null - }, - "world_11": { - "name": "Odessa", - "callsign": "OD", - "beacon_type": 8, - "hertz": 348000, - "channel": null - }, - "world_12": { - "name": "Yalta", - "callsign": "BS", - "beacon_type": 8, - "hertz": 300500, - "channel": null - }, - "world_13": { - "name": "Stavropol", - "callsign": "KT", - "beacon_type": 8, - "hertz": 730000, - "channel": null - }, - "world_14": { - "name": "Yegorlykskaya", - "callsign": "ER", - "beacon_type": 8, - "hertz": 435000, - "channel": null - }, - "world_15": { - "name": "Komisarivka", - "callsign": "KM", - "beacon_type": 8, - "hertz": 950000, - "channel": null - }, - "world_16": { - "name": "Skadovsk", - "callsign": "SK", - "beacon_type": 8, - "hertz": 680000, - "channel": null - }, - "world_17": { - "name": "Gali", - "callsign": "DA", - "beacon_type": 8, - "hertz": 525000, - "channel": null - }, - "world_18": { - "name": "Mukhrani", - "callsign": "DF", - "beacon_type": 8, - "hertz": 520000, - "channel": null - }, - "world_19": { - "name": "Ladozhskaya", - "callsign": "RF", - "beacon_type": 8, - "hertz": 324000, - "channel": null - }, - "world_20": { - "name": "Teplorechensky", - "callsign": "FM", - "beacon_type": 8, - "hertz": 1182000, - "channel": null - }, - "world_21": { - "name": "Kalaus", - "callsign": "BJ", - "beacon_type": 8, - "hertz": 735000, - "channel": null - }, - "world_22": { - "name": "Nikolaev-Kulbakino", - "callsign": "NK", - "beacon_type": 8, - "hertz": 1030000, - "channel": null - }, - "world_23": { - "name": "Manychsky", - "callsign": "MN", - "beacon_type": 8, - "hertz": 705000, - "channel": null - }, - "world_24": { - "name": "Kerch", - "callsign": "KC", - "beacon_type": 8, - "hertz": 1050000, - "channel": null - }, - "world_25": { - "name": "TaganrogYuzhny", - "callsign": "TY", - "beacon_type": 8, - "hertz": 720000, - "channel": null - }, - "world_26": { - "name": "Ali", - "callsign": "AL", - "beacon_type": 8, - "hertz": 353000, - "channel": null - }, - "world_27": { - "name": "Elista", - "callsign": "SA", - "beacon_type": 8, - "hertz": 311000, - "channel": null - }, - "world_28": { - "name": "Ryazanskaya", - "callsign": "XT", - "beacon_type": 8, - "hertz": 312000, - "channel": null - }, - "world_29": { - "name": "Kakhovka", - "callsign": "KH", - "beacon_type": 8, - "hertz": 485000, - "channel": null - }, - "world_30": { - "name": "Vesely", - "callsign": "WS", - "beacon_type": 8, - "hertz": 641000, - "channel": null - }, - "world_31": { - "name": "Odessa", - "callsign": "WR", - "beacon_type": 8, - "hertz": 309500, - "channel": null - }, - "world_32": { - "name": "Armavir", - "callsign": "VM", - "beacon_type": 8, - "hertz": 740000, - "channel": null - }, - "world_33": { - "name": "Grozny", - "callsign": "WK", - "beacon_type": 8, - "hertz": 830000, - "channel": null - }, - "world_34": { - "name": "Tiraspol", - "callsign": "TH", - "beacon_type": 8, - "hertz": 515000, - "channel": null - }, - "world_35": { - "name": "Simferopol", - "callsign": "KC", - "beacon_type": 8, - "hertz": 580000, - "channel": null - }, - "world_36": { - "name": "Sultanskoye", - "callsign": "SN", - "beacon_type": 8, - "hertz": 866000, - "channel": null - }, - "world_37": { - "name": "Buyalyk", - "callsign": "DW", - "beacon_type": 8, - "hertz": 625000, - "channel": null - }, - "world_38": { - "name": "Sarmakovo", - "callsign": "SR", - "beacon_type": 8, - "hertz": 907000, - "channel": null - }, - "world_39": { - "name": "Tendrovskiy", - "callsign": "TD", - "beacon_type": 8, - "hertz": 309500, - "channel": null - }, - "world_40": { - "name": "Sukhoy", - "callsign": "SH", - "beacon_type": 8, - "hertz": 862000, - "channel": null - }, - "world_41": { - "name": "Dzhubga", - "callsign": "DV", - "beacon_type": 8, - "hertz": 420000, - "channel": null - }, - "world_42": { - "name": "Genichesk", - "callsign": "GE", - "beacon_type": 8, - "hertz": 300500, - "channel": null - }, - "world_43": { - "name": "Primorsko-Akhtarsk", - "callsign": "GW", - "beacon_type": 8, - "hertz": 920000, - "channel": null - }, - "world_44": { - "name": "Yasnaya", - "callsign": "QG", - "beacon_type": 8, - "hertz": 435000, - "channel": null - }, - "world_45": { - "name": "Alushta", - "callsign": "AL", - "beacon_type": 8, - "hertz": 384000, - "channel": null - }, - "world_46": { - "name": "Dobrushyn", - "callsign": "DO", - "beacon_type": 8, - "hertz": 1175000, - "channel": null - }, - "world_47": { - "name": "Bolshevik", - "callsign": "ND", - "beacon_type": 8, - "hertz": 507000, - "channel": null - }, - "world_48": { - "name": "Peredovay", - "callsign": "PR", - "beacon_type": 8, - "hertz": 1210000, - "channel": null - }, - "world_49": { - "name": "Parutine", - "callsign": "PA", - "beacon_type": 8, - "hertz": 905000, - "channel": null - }, - "world_50": { - "name": "Gori", - "callsign": "OE", - "beacon_type": 8, - "hertz": 462000, - "channel": null - }, - "world_51": { - "name": "Liubymivka", - "callsign": "LY", - "beacon_type": 8, - "hertz": 670000, - "channel": null - }, - "world_52": { - "name": "Mariupol", - "callsign": "MA", - "beacon_type": 8, - "hertz": 770000, - "channel": null - }, - "world_53": { - "name": "Akhilleon", - "callsign": "AH", - "beacon_type": 8, - "hertz": 300500, - "channel": null - }, - "world_54": { - "name": "Nikolaev-Matveyevka", - "callsign": "NK", - "beacon_type": 8, - "hertz": 1030000, - "channel": null - }, - "world_55": { - "name": "Melitopol", - "callsign": "NE", - "beacon_type": 8, - "hertz": 740000, - "channel": null - }, - "world_56": { - "name": "TchervonoLissya", - "callsign": "LE", - "beacon_type": 8, - "hertz": 395000, - "channel": null - }, - "world_57": { - "name": "Tikhoretsk", - "callsign": "UH", - "beacon_type": 8, - "hertz": 528000, - "channel": null - }, - "world_58": { - "name": "Rostov-Na-Donu", - "callsign": "RE", - "beacon_type": 8, - "hertz": 320000, - "channel": null - }, - "world_59": { - "name": "Lazarevskoye", - "callsign": "LA", - "beacon_type": 8, - "hertz": 307000, - "channel": null - }, - "world_60": { - "name": "Berdyansk", - "callsign": "BD", - "beacon_type": 8, - "hertz": 342000, - "channel": null - }, - "world_61": { - "name": "Kropotkin", - "callsign": "KP", - "beacon_type": 8, - "hertz": 214000, - "channel": null - }, - "world_62": { - "name": "Lymans-Ke", - "callsign": "LA", - "beacon_type": 8, - "hertz": 750000, - "channel": null - }, - "world_63": { - "name": "Krasny", - "callsign": "KS", - "beacon_type": 8, - "hertz": 1025000, - "channel": null - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/falklands.json b/resources/dcs/beacons/falklands.json deleted file mode 100644 index ad9aaba7b..000000000 --- a/resources/dcs/beacons/falklands.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "airfield14_0": { - "name": "ELCALACAFE", - "callsign": "EC", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield14_1": { - "name": "ELCALAFATE", - "callsign": "ec", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield14_2": { - "name": "ECA", - "callsign": "ECA", - "beacon_type": 3, - "hertz": 114700000, - "channel": 94 - }, - "airfield2_0": { - "name": "MTPLEASANT", - "callsign": "imp", - "beacon_type": 13, - "hertz": 111900000, - "channel": null - }, - "airfield2_1": { - "name": "MP", - "callsign": "MP", - "beacon_type": 9, - "hertz": 380000, - "channel": null - }, - "airfield2_2": { - "name": "MPA", - "callsign": "MPA", - "beacon_type": 4, - "hertz": 112200000, - "channel": 59 - }, - "airfield2_3": { - "name": "MTP", - "callsign": "MTP", - "beacon_type": 1, - "hertz": 114700000, - "channel": 94 - }, - "airfield2_4": { - "name": "MTPLEASANT", - "callsign": "IMP", - "beacon_type": 14, - "hertz": 111900000, - "channel": null - }, - "airfield1_0": { - "name": "stanleyairport", - "callsign": "SA", - "beacon_type": 9, - "hertz": 305000, - "channel": null - }, - "airfield1_1": { - "name": "DFO", - "callsign": "DFO", - "beacon_type": 1, - "hertz": 113300000, - "channel": null - }, - "airfield13_0": { - "name": "PUERTO NATALES", - "callsign": "PNT", - "beacon_type": 3, - "hertz": 115900000, - "channel": 106 - }, - "airfield12_0": { - "name": "Puerto Williams", - "callsign": "PWL", - "beacon_type": 3, - "hertz": 114900000, - "channel": 96 - }, - "airfield9_0": { - "name": "ptarenas", - "callsign": "inas", - "beacon_type": 14, - "hertz": 109900000, - "channel": null - }, - "airfield9_1": { - "name": "", - "callsign": "INAS", - "beacon_type": 13, - "hertz": 109900000, - "channel": null - }, - "airfield9_2": { - "name": "NAS", - "callsign": "NAS", - "beacon_type": 3, - "hertz": 114100000, - "channel": null - }, - "airfield9_3": { - "name": "NAS", - "callsign": "NAS", - "beacon_type": 8, - "hertz": 270000, - "channel": null - }, - "airfield5_0": { - "name": "GAL", - "callsign": "GAL", - "beacon_type": 3, - "hertz": 116700000, - "channel": 114 - }, - "airfield5_1": { - "name": "RIOGALLEGOS", - "callsign": "gl", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield5_2": { - "name": "RIOGALLEGOS", - "callsign": "gl", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield6_0": { - "name": "RIOGRANDE", - "callsign": "gr", - "beacon_type": 13, - "hertz": 109500000, - "channel": null - }, - "airfield6_1": { - "name": "GRA", - "callsign": "GRA", - "beacon_type": 3, - "hertz": 117300000, - "channel": 120 - }, - "airfield6_2": { - "name": "RIOGRANDE", - "callsign": "gr", - "beacon_type": 14, - "hertz": 109500000, - "channel": null - }, - "airfield6_3": { - "name": "riograndendb", - "callsign": "P", - "beacon_type": 9, - "hertz": 265000, - "channel": null - }, - "airfield6_4": { - "name": "riogrande", - "callsign": "gra", - "beacon_type": 4, - "hertz": 1000000, - "channel": 31 - }, - "airfield20_0": { - "name": "BIO", - "callsign": "BIO", - "beacon_type": 9, - "hertz": 205000000, - "channel": null - }, - "airfield11_0": { - "name": "San Julian", - "callsign": "", - "beacon_type": 3, - "hertz": 117700000, - "channel": null - }, - "airfield7_0": { - "name": "RIOGRANDE", - "callsign": "us", - "beacon_type": 13, - "hertz": 111300000, - "channel": null - }, - "airfield7_1": { - "name": "Ushuaia", - "callsign": "us", - "beacon_type": 14, - "hertz": 111300000, - "channel": null - }, - "airfield7_2": { - "name": "USU", - "callsign": "USU", - "beacon_type": 1, - "hertz": 113700000, - "channel": 84 - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/marianaislands.json b/resources/dcs/beacons/marianaislands.json deleted file mode 100644 index 67d660bf0..000000000 --- a/resources/dcs/beacons/marianaislands.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "world_0": { - "name": "MTMACAJNA", - "callsign": "AJA", - "beacon_type": 8, - "hertz": 385000, - "channel": null - }, - "world_1": { - "name": "Nimitz", - "callsign": "UNZ", - "beacon_type": 5, - "hertz": 115800000, - "channel": 105 - }, - "world_2": { - "name": "SAIPAN", - "callsign": "SN", - "beacon_type": 8, - "hertz": 312000, - "channel": null - }, - "airfield6_0": { - "name": "ANDERSEN", - "callsign": "UAM", - "beacon_type": 4, - "hertz": null, - "channel": 54 - }, - "airfield6_1": { - "name": "", - "callsign": "IPMY", - "beacon_type": 14, - "hertz": 110150000, - "channel": null - }, - "airfield6_2": { - "name": "", - "callsign": "IUAM", - "beacon_type": 14, - "hertz": 110100000, - "channel": null - }, - "airfield6_3": { - "name": "", - "callsign": "IYIG", - "beacon_type": 14, - "hertz": 109350000, - "channel": null - }, - "airfield6_4": { - "name": "", - "callsign": "IAND", - "beacon_type": 14, - "hertz": 109300000, - "channel": null - }, - "airfield6_5": { - "name": "", - "callsign": "IUAM", - "beacon_type": 13, - "hertz": 110100000, - "channel": null - }, - "airfield6_6": { - "name": "", - "callsign": "IAND", - "beacon_type": 13, - "hertz": 109300000, - "channel": null - }, - "airfield6_7": { - "name": "", - "callsign": "IYIG", - "beacon_type": 13, - "hertz": 109350000, - "channel": null - }, - "airfield6_8": { - "name": "", - "callsign": "IPMY", - "beacon_type": 13, - "hertz": 110150000, - "channel": null - }, - "airfield4_0": { - "name": "", - "callsign": "IGUM", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield4_1": { - "name": "", - "callsign": "PGUM", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield4_2": { - "name": "", - "callsign": "IAWD", - "beacon_type": 13, - "hertz": 110900000, - "channel": null - }, - "airfield4_3": { - "name": "", - "callsign": "PGUM", - "beacon_type": 14, - "hertz": 110900000, - "channel": null - }, - "airfield1_0": { - "name": "ROTA", - "callsign": "GRO", - "beacon_type": 8, - "hertz": 332000, - "channel": null - }, - "airfield2_0": { - "name": "", - "callsign": "IGSN", - "beacon_type": 13, - "hertz": 109900000, - "channel": null - }, - "airfield2_1": { - "name": "", - "callsign": "PGSN", - "beacon_type": 14, - "hertz": 109900000, - "channel": null - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/nevada.json b/resources/dcs/beacons/nevada.json deleted file mode 100644 index 512f72a7c..000000000 --- a/resources/dcs/beacons/nevada.json +++ /dev/null @@ -1,317 +0,0 @@ -{ - "airfield1_0": { - "name": "Creech", - "callsign": "ICRR", - "beacon_type": 14, - "hertz": 108700000, - "channel": 24 - }, - "airfield1_1": { - "name": "Creech", - "callsign": "ICRR", - "beacon_type": 13, - "hertz": 108700000, - "channel": 24 - }, - "airfield1_2": { - "name": "Creech", - "callsign": "ICRS", - "beacon_type": 13, - "hertz": 108500000, - "channel": 22 - }, - "airfield1_3": { - "name": "Creech", - "callsign": "ICRS", - "beacon_type": 14, - "hertz": 108500000, - "channel": 22 - }, - "airfield1_4": { - "name": "Creech", - "callsign": "INS", - "beacon_type": 4, - "hertz": null, - "channel": 87 - }, - "airfield2_0": { - "name": "Groom-Lake", - "callsign": "GLRI", - "beacon_type": 13, - "hertz": 109300000, - "channel": 30 - }, - "airfield2_1": { - "name": "Groom-Lake", - "callsign": "GLRI", - "beacon_type": 14, - "hertz": 109300000, - "channel": 30 - }, - "airfield2_2": { - "name": "Groom-Lake", - "callsign": "GRL", - "beacon_type": 4, - "hertz": null, - "channel": 18 - }, - "airfield3_0": { - "name": "McCarran-International", - "callsign": "I-RLE", - "beacon_type": 14, - "hertz": 111750000, - "channel": null - }, - "airfield3_1": { - "name": "McCarran-International", - "callsign": "I-LAS", - "beacon_type": 14, - "hertz": 110300000, - "channel": 40 - }, - "airfield3_2": { - "name": "McCarran-International", - "callsign": "I-RLE", - "beacon_type": 13, - "hertz": 111750000, - "channel": null - }, - "airfield3_3": { - "name": "McCarran-International", - "callsign": "I-LAS", - "beacon_type": 13, - "hertz": 110300000, - "channel": 40 - }, - "airfield3_4": { - "name": "McCarran-International", - "callsign": "LAS", - "beacon_type": 5, - "hertz": 116900000, - "channel": 116 - }, - "airfield4_0": { - "name": "Nellis", - "callsign": "IDIQ", - "beacon_type": 14, - "hertz": 109100000, - "channel": null - }, - "airfield4_1": { - "name": "Nellis", - "callsign": "LSV", - "beacon_type": 4, - "hertz": null, - "channel": 12 - }, - "airfield4_2": { - "name": "Nellis", - "callsign": "IDIQ", - "beacon_type": 13, - "hertz": 109100000, - "channel": null - }, - "airfield15_0": { - "name": "North-Las-Vegas", - "callsign": "I-HWG", - "beacon_type": 13, - "hertz": 110700000, - "channel": null - }, - "airfield15_1": { - "name": "North-Las-Vegas", - "callsign": "I-HWG", - "beacon_type": 14, - "hertz": 110700000, - "channel": null - }, - "airfield18_0": { - "name": "Tonopah-Test-Range", - "callsign": "I-RVP", - "beacon_type": 13, - "hertz": 108300000, - "channel": null - }, - "airfield18_1": { - "name": "Tonopah-Test-Range", - "callsign": "I-UVV", - "beacon_type": 13, - "hertz": 111700000, - "channel": null - }, - "airfield18_2": { - "name": "Tonopah-Test-Range", - "callsign": "I-UVV", - "beacon_type": 14, - "hertz": 111700000, - "channel": null - }, - "airfield18_3": { - "name": "Tonopah-Test-Range", - "callsign": "I-RVP", - "beacon_type": 14, - "hertz": 108300000, - "channel": null - }, - "airfield18_4": { - "name": "Silverbow", - "callsign": "TQQ", - "beacon_type": 5, - "hertz": 113000000, - "channel": 77 - }, - "world_0": { - "name": "St George", - "callsign": "UTI", - "beacon_type": 3, - "hertz": 108600000, - "channel": 23 - }, - "world_1": { - "name": "Grand Canyon", - "callsign": "GCN", - "beacon_type": 3, - "hertz": 113100000, - "channel": 78 - }, - "world_2": { - "name": "Kingman", - "callsign": "IGM", - "beacon_type": 3, - "hertz": 108800000, - "channel": 25 - }, - "world_3": { - "name": "Colorado City", - "callsign": "AZC", - "beacon_type": 9, - "hertz": 403000, - "channel": null - }, - "world_4": { - "name": "Meggi", - "callsign": "EC", - "beacon_type": 9, - "hertz": 217000, - "channel": null - }, - "world_5": { - "name": "Daggett", - "callsign": "DAG", - "beacon_type": 5, - "hertz": 113200000, - "channel": 79 - }, - "world_6": { - "name": "Hector", - "callsign": "HEC", - "beacon_type": 5, - "hertz": 112700000, - "channel": 74 - }, - "world_7": { - "name": "Needles", - "callsign": "EED", - "beacon_type": 5, - "hertz": 115200000, - "channel": 99 - }, - "world_8": { - "name": "Milford", - "callsign": "MLF", - "beacon_type": 5, - "hertz": 112100000, - "channel": 58 - }, - "world_9": { - "name": "GOFFS", - "callsign": "GFS", - "beacon_type": 5, - "hertz": 114400000, - "channel": 91 - }, - "world_10": { - "name": "Tonopah", - "callsign": "TPH", - "beacon_type": 5, - "hertz": 117200000, - "channel": 119 - }, - "world_11": { - "name": "Mina", - "callsign": "MVA", - "beacon_type": 5, - "hertz": 115100000, - "channel": 98 - }, - "world_12": { - "name": "Wilson Creek", - "callsign": "ILC", - "beacon_type": 5, - "hertz": 116300000, - "channel": 110 - }, - "world_13": { - "name": "Cedar City", - "callsign": "CDC", - "beacon_type": 5, - "hertz": 117300000, - "channel": 120 - }, - "world_14": { - "name": "Bryce Canyon", - "callsign": "BCE", - "beacon_type": 5, - "hertz": 112800000, - "channel": 75 - }, - "world_15": { - "name": "Mormon Mesa", - "callsign": "MMM", - "beacon_type": 5, - "hertz": 114300000, - "channel": 90 - }, - "world_16": { - "name": "Beatty", - "callsign": "BTY", - "beacon_type": 5, - "hertz": 114700000, - "channel": 94 - }, - "world_17": { - "name": "Bishop", - "callsign": "BIH", - "beacon_type": 5, - "hertz": 109600000, - "channel": 33 - }, - "world_18": { - "name": "Coaldale", - "callsign": "OAL", - "beacon_type": 5, - "hertz": 117700000, - "channel": 124 - }, - "world_19": { - "name": "Peach Springs", - "callsign": "PGS", - "beacon_type": 5, - "hertz": 112000000, - "channel": 57 - }, - "world_20": { - "name": "Boulder City", - "callsign": "BLD", - "beacon_type": 5, - "hertz": 116700000, - "channel": 114 - }, - "world_21": { - "name": "Mercury", - "callsign": "MCY", - "beacon_type": 9, - "hertz": 326000, - "channel": null - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/normandy.json b/resources/dcs/beacons/normandy.json deleted file mode 100644 index 9e26dfeeb..000000000 --- a/resources/dcs/beacons/normandy.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/resources/dcs/beacons/persiangulf.json b/resources/dcs/beacons/persiangulf.json deleted file mode 100644 index 494cc7b0a..000000000 --- a/resources/dcs/beacons/persiangulf.json +++ /dev/null @@ -1,709 +0,0 @@ -{ - "world_0": { - "name": "Kish", - "callsign": "KIS", - "beacon_type": 3, - "hertz": 117400000, - "channel": 121 - }, - "world_1": { - "name": "DohaAirport", - "callsign": "DIA", - "beacon_type": 3, - "hertz": 112400000, - "channel": 71 - }, - "world_2": { - "name": "HamadInternationalAirport", - "callsign": "DOH", - "beacon_type": 3, - "hertz": 114400000, - "channel": 91 - }, - "world_3": { - "name": "DezfulAirport", - "callsign": "DZF", - "beacon_type": 8, - "hertz": 293000, - "channel": null - }, - "world_4": { - "name": "AbadanIntAirport", - "callsign": "ABD", - "beacon_type": 3, - "hertz": 115100000, - "channel": 98 - }, - "world_5": { - "name": "AhvazIntAirport", - "callsign": "AWZ", - "beacon_type": 3, - "hertz": 114000000, - "channel": 87 - }, - "world_6": { - "name": "AghajariAirport", - "callsign": "AJR", - "beacon_type": 3, - "hertz": 114900000, - "channel": 96 - }, - "world_7": { - "name": "BirjandIntAirport", - "callsign": "BJD", - "beacon_type": 3, - "hertz": 113500000, - "channel": 82 - }, - "world_8": { - "name": "BushehrIntAirport", - "callsign": "BUZ", - "beacon_type": 3, - "hertz": 117450000, - "channel": 121 - }, - "world_9": { - "name": "KonarakAirport", - "callsign": "CBH", - "beacon_type": 3, - "hertz": 115600000, - "channel": 103 - }, - "world_10": { - "name": "IsfahanIntAirport", - "callsign": "ISN", - "beacon_type": 3, - "hertz": 113200000, - "channel": 79 - }, - "world_11": { - "name": "KhoramabadAirport", - "callsign": "KRD", - "beacon_type": 3, - "hertz": 113750000, - "channel": 84 - }, - "world_12": { - "name": "PersianGulfIntAirport", - "callsign": "PRG", - "beacon_type": 3, - "hertz": 112100000, - "channel": 58 - }, - "world_13": { - "name": "YasoujAirport", - "callsign": "YSJ", - "beacon_type": 3, - "hertz": 116550000, - "channel": 112 - }, - "world_14": { - "name": "BamAirport", - "callsign": "BAM", - "beacon_type": 3, - "hertz": 114900000, - "channel": 96 - }, - "world_15": { - "name": "MahshahrAirport", - "callsign": "MAH", - "beacon_type": 3, - "hertz": 115800000, - "channel": 105 - }, - "world_16": { - "name": "IranShahrAirport", - "callsign": "ISR", - "beacon_type": 3, - "hertz": 117000000, - "channel": 117 - }, - "world_17": { - "name": "LamerdAirport", - "callsign": "LAM", - "beacon_type": 3, - "hertz": 117000000, - "channel": 117 - }, - "world_18": { - "name": "SirjanAirport", - "callsign": "SRJ", - "beacon_type": 3, - "hertz": 114600000, - "channel": 93 - }, - "world_19": { - "name": "YazdIntAirport", - "callsign": "YZD", - "beacon_type": 3, - "hertz": 117700000, - "channel": 124 - }, - "world_20": { - "name": "ZabolAirport", - "callsign": "ZAL", - "beacon_type": 3, - "hertz": 113100000, - "channel": 78 - }, - "world_21": { - "name": "ZahedanIntAirport", - "callsign": "ZDN", - "beacon_type": 3, - "hertz": 116000000, - "channel": 107 - }, - "world_22": { - "name": "RafsanjanAirport", - "callsign": "RAF", - "beacon_type": 3, - "hertz": 112300000, - "channel": 70 - }, - "world_23": { - "name": "SaravanAirport", - "callsign": "SRN", - "beacon_type": 3, - "hertz": 114100000, - "channel": 88 - }, - "world_24": { - "name": "BuHasa", - "callsign": "BH", - "beacon_type": 2, - "hertz": 309000000, - "channel": null - }, - "airfield22_0": { - "name": "AbuDhabiInt", - "callsign": "ADV", - "beacon_type": 2, - "hertz": 114250000, - "channel": 119 - }, - "airfield22_1": { - "name": "ABUDHABI", - "callsign": "ADV", - "beacon_type": 1, - "hertz": 114250000, - "channel": null - }, - "airfield1_0": { - "name": "Abumusa", - "callsign": "ABM", - "beacon_type": 2, - "hertz": 285000, - "channel": 101 - }, - "airfield25_0": { - "name": "AlAinInt", - "callsign": "ALN", - "beacon_type": 3, - "hertz": 112600000, - "channel": 119 - }, - "airfield23_0": { - "name": "AlBateenInt", - "callsign": "ALB", - "beacon_type": 1, - "hertz": 114000000, - "channel": 119 - }, - "airfield2_0": { - "name": "BandarAbbas", - "callsign": "BND", - "beacon_type": 3, - "hertz": 117200000, - "channel": 119 - }, - "airfield2_1": { - "name": "BandarAbbas", - "callsign": "BND", - "beacon_type": 8, - "hertz": 250000, - "channel": null - }, - "airfield2_2": { - "name": "", - "callsign": "IBND", - "beacon_type": 13, - "hertz": 109900000, - "channel": null - }, - "airfield2_3": { - "name": "", - "callsign": "IBND", - "beacon_type": 14, - "hertz": 109900000, - "channel": null - }, - "airfield2_4": { - "name": "BandarAbbas", - "callsign": "BND", - "beacon_type": 4, - "hertz": null, - "channel": 78 - }, - "airfield21_0": { - "name": "BandarEJask", - "callsign": "KHM", - "beacon_type": 3, - "hertz": 116300000, - "channel": null - }, - "airfield21_1": { - "name": "JASK", - "callsign": "JSK", - "beacon_type": 8, - "hertz": 349000, - "channel": null - }, - "airfield21_2": { - "name": "", - "callsign": "JSK", - "beacon_type": 4, - "hertz": null, - "channel": 110 - }, - "airfield3_0": { - "name": "BandarLengeh", - "callsign": "LEN", - "beacon_type": 8, - "hertz": 408000, - "channel": null - }, - "airfield3_1": { - "name": "BandarLengeh", - "callsign": "LEN", - "beacon_type": 3, - "hertz": 114800000, - "channel": 95 - }, - "airfield4_0": { - "name": "", - "callsign": "MMA", - "beacon_type": 14, - "hertz": 109100000, - "channel": 28 - }, - "airfield4_1": { - "name": "", - "callsign": "LMA", - "beacon_type": 14, - "hertz": 108700000, - "channel": 24 - }, - "airfield4_2": { - "name": "", - "callsign": "IMA", - "beacon_type": 14, - "hertz": 111100000, - "channel": 48 - }, - "airfield4_3": { - "name": "", - "callsign": "RMA", - "beacon_type": 14, - "hertz": 108700000, - "channel": 24 - }, - "airfield4_4": { - "name": "", - "callsign": "MMA", - "beacon_type": 13, - "hertz": 109100000, - "channel": 28 - }, - "airfield4_5": { - "name": "", - "callsign": "RMA", - "beacon_type": 13, - "hertz": 108700000, - "channel": 24 - }, - "airfield4_6": { - "name": "", - "callsign": "LMA", - "beacon_type": 13, - "hertz": 108700000, - "channel": 24 - }, - "airfield4_7": { - "name": "", - "callsign": "IMA", - "beacon_type": 13, - "hertz": 111100000, - "channel": 48 - }, - "airfield4_8": { - "name": "AlDhafra", - "callsign": "MA", - "beacon_type": 5, - "hertz": 114900000, - "channel": 96 - }, - "airfield5_0": { - "name": "", - "callsign": "IDBW", - "beacon_type": 13, - "hertz": 109500000, - "channel": null - }, - "airfield5_1": { - "name": "", - "callsign": "IDBR", - "beacon_type": 13, - "hertz": 110100000, - "channel": null - }, - "airfield5_2": { - "name": "", - "callsign": "IDBE", - "beacon_type": 13, - "hertz": 111300000, - "channel": null - }, - "airfield5_3": { - "name": "", - "callsign": "IDBL", - "beacon_type": 13, - "hertz": 110900000, - "channel": null - }, - "airfield5_4": { - "name": "", - "callsign": "IDBL", - "beacon_type": 14, - "hertz": 110900000, - "channel": null - }, - "airfield5_5": { - "name": "", - "callsign": "IDBR", - "beacon_type": 14, - "hertz": 110100000, - "channel": null - }, - "airfield5_6": { - "name": "", - "callsign": "IDBE", - "beacon_type": 14, - "hertz": 111300000, - "channel": null - }, - "airfield5_7": { - "name": "", - "callsign": "IDBW", - "beacon_type": 14, - "hertz": 109500000, - "channel": null - }, - "airfield6_0": { - "name": "", - "callsign": "IJEA", - "beacon_type": 13, - "hertz": 111750000, - "channel": null - }, - "airfield6_1": { - "name": "", - "callsign": "IJWA", - "beacon_type": 14, - "hertz": 109750000, - "channel": null - }, - "airfield6_2": { - "name": "", - "callsign": "IJEA", - "beacon_type": 14, - "hertz": 111750000, - "channel": null - }, - "airfield6_3": { - "name": "", - "callsign": "IJWA", - "beacon_type": 13, - "hertz": 109750000, - "channel": null - }, - "airfield7_0": { - "name": "Fujairah", - "callsign": "FJV", - "beacon_type": 3, - "hertz": 113800000, - "channel": 85 - }, - "airfield7_1": { - "name": "", - "callsign": "IFJR", - "beacon_type": 14, - "hertz": 111500000, - "channel": null - }, - "airfield7_2": { - "name": "", - "callsign": "IFJR", - "beacon_type": 13, - "hertz": 111500000, - "channel": null - }, - "airfield9_0": { - "name": "Havadarya", - "callsign": "HDR", - "beacon_type": 4, - "hertz": 111000000, - "channel": 47 - }, - "airfield9_1": { - "name": "", - "callsign": "IBHD", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield9_2": { - "name": "", - "callsign": "IBHD", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield27_0": { - "name": "Jiroft", - "callsign": "JIR", - "beacon_type": 9, - "hertz": 276000, - "channel": null - }, - "airfield18_0": { - "name": "KERMAN", - "callsign": "KER", - "beacon_type": 4, - "hertz": 122500000, - "channel": 97 - }, - "airfield18_1": { - "name": "KERMAN", - "callsign": "KER", - "beacon_type": 3, - "hertz": 112000000, - "channel": 57 - }, - "airfield18_2": { - "name": "KERMAN", - "callsign": "KER", - "beacon_type": 2, - "hertz": 290000000, - "channel": null - }, - "airfield10_0": { - "name": "", - "callsign": "IBKS", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield10_1": { - "name": "", - "callsign": "IBKS", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield24_0": { - "name": "KishIsland", - "callsign": "KIH", - "beacon_type": 8, - "hertz": 201000, - "channel": null - }, - "airfield24_1": { - "name": "KishIsland", - "callsign": "KIH", - "beacon_type": 4, - "hertz": null, - "channel": 112 - }, - "airfield11_0": { - "name": "LAR", - "callsign": "LAR", - "beacon_type": 3, - "hertz": 117900000, - "channel": null - }, - "airfield11_1": { - "name": "LAR", - "callsign": "OISL", - "beacon_type": 8, - "hertz": 224000, - "channel": null - }, - "airfield26_0": { - "name": "LavanIsland", - "callsign": "LVA", - "beacon_type": 3, - "hertz": 116850000, - "channel": 115 - }, - "airfield26_1": { - "name": "LavanIsland", - "callsign": "LVA", - "beacon_type": 8, - "hertz": 310000, - "channel": 0 - }, - "airfield29_0": { - "name": "LiwaAirbase", - "callsign": "OMLW", - "beacon_type": 5, - "hertz": 117400000, - "channel": 121 - }, - "airfield12_0": { - "name": "Minhad", - "callsign": "MIN", - "beacon_type": 4, - "hertz": 115200000, - "channel": 99 - }, - "airfield12_1": { - "name": "", - "callsign": "IMNW", - "beacon_type": 13, - "hertz": 110700000, - "channel": null - }, - "airfield12_2": { - "name": "", - "callsign": "IMNW", - "beacon_type": 14, - "hertz": 110700000, - "channel": null - }, - "airfield12_3": { - "name": "", - "callsign": "IMNR", - "beacon_type": 13, - "hertz": 110750000, - "channel": null - }, - "airfield12_4": { - "name": "", - "callsign": "IMNR", - "beacon_type": 14, - "hertz": 110750000, - "channel": null - }, - "airfield13_0": { - "name": "GheshmIsland", - "callsign": "KHM", - "beacon_type": 8, - "hertz": 233000, - "channel": null - }, - "airfield13_1": { - "name": "GheshmIsland", - "callsign": "KHM", - "beacon_type": 3, - "hertz": 117100000, - "channel": null - }, - "airfield28_0": { - "name": "RasAlKhaimah", - "callsign": "OMRK", - "beacon_type": 3, - "hertz": 113600000, - "channel": 83 - }, - "airfield20_0": { - "name": "SasAlNakheel", - "callsign": "SAS", - "beacon_type": 3, - "hertz": 128925000, - "channel": 119 - }, - "airfield14_0": { - "name": "", - "callsign": "ISRE", - "beacon_type": 13, - "hertz": 108550000, - "channel": null - }, - "airfield14_1": { - "name": "", - "callsign": "ISHW", - "beacon_type": 13, - "hertz": 111950000, - "channel": null - }, - "airfield14_2": { - "name": "", - "callsign": "ISHW", - "beacon_type": 14, - "hertz": 111950000, - "channel": null - }, - "airfield14_3": { - "name": "", - "callsign": "ISRE", - "beacon_type": 14, - "hertz": 108550000, - "channel": null - }, - "airfield19_0": { - "name": "SHIRAZ", - "callsign": "SYZ", - "beacon_type": 3, - "hertz": 117800000, - "channel": 125 - }, - "airfield19_1": { - "name": "SHIRAZ", - "callsign": "SYZ1", - "beacon_type": 4, - "hertz": 114700000, - "channel": 94 - }, - "airfield19_2": { - "name": "SHIRAZ", - "callsign": "SR", - "beacon_type": 8, - "hertz": 205000, - "channel": null - }, - "airfield19_3": { - "name": "", - "callsign": "ISYZ", - "beacon_type": 14, - "hertz": 108500000, - "channel": null - }, - "airfield19_4": { - "name": "", - "callsign": "ISYZ", - "beacon_type": 13, - "hertz": 108500000, - "channel": null - }, - "airfield15_0": { - "name": "SirriIsland", - "callsign": "SIR", - "beacon_type": 8, - "hertz": 300000, - "channel": null - }, - "airfield15_1": { - "name": "SirriIsland", - "callsign": "SIR", - "beacon_type": 3, - "hertz": 113750000, - "channel": null - }, - "airfield16_0": { - "name": "Kochak", - "callsign": "KCK", - "beacon_type": 4, - "hertz": 114200000, - "channel": 89 - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/sinai.json b/resources/dcs/beacons/sinai.json deleted file mode 100644 index fcc89889e..000000000 --- a/resources/dcs/beacons/sinai.json +++ /dev/null @@ -1,1045 +0,0 @@ -{ - "world_0": { - "name": "Banias", - "callsign": "BAN", - "beacon_type": 8, - "hertz": 304000, - "channel": 0 - }, - "world_1": { - "name": "QueenAlia", - "callsign": "MDB", - "beacon_type": 8, - "hertz": 399000, - "channel": 0 - }, - "world_2": { - "name": "QueenAlia", - "callsign": "QAA", - "beacon_type": 3, - "hertz": 115200000, - "channel": 99 - }, - "world_3": { - "name": "Damascus", - "callsign": "DAM", - "beacon_type": 3, - "hertz": 116000000, - "channel": 107 - }, - "world_4": { - "name": "Beirut", - "callsign": "BOD", - "beacon_type": 8, - "hertz": 351000, - "channel": 0 - }, - "world_5": { - "name": "Asyut", - "callsign": "AST", - "beacon_type": 3, - "hertz": 117700000, - "channel": 124 - }, - "world_6": { - "name": "Aqaba", - "callsign": "AQC", - "beacon_type": 8, - "hertz": 326000, - "channel": 0 - }, - "world_7": { - "name": "Mezze", - "callsign": "MEZ", - "beacon_type": 8, - "hertz": 358000, - "channel": 0 - }, - "world_8": { - "name": "Kariatain", - "callsign": "KTN", - "beacon_type": 8, - "hertz": 373000, - "channel": 0 - }, - "world_9": { - "name": "BasselAlAssad", - "callsign": "LTK", - "beacon_type": 3, - "hertz": 114800000, - "channel": 95 - }, - "world_10": { - "name": "Taba", - "callsign": "TBA", - "beacon_type": 3, - "hertz": 114500000, - "channel": 92 - }, - "world_11": { - "name": "Nuweibaa", - "callsign": "NWB", - "beacon_type": 8, - "hertz": 288000, - "channel": 0 - }, - "world_12": { - "name": "Jerusalem", - "callsign": "IRM", - "beacon_type": 8, - "hertz": 336000, - "channel": 0 - }, - "world_13": { - "name": "Almaza", - "callsign": "A", - "beacon_type": 8, - "hertz": 490000, - "channel": 0 - }, - "world_14": { - "name": "Amman", - "callsign": "AMN", - "beacon_type": 3, - "hertz": 116300000, - "channel": 110 - }, - "world_15": { - "name": "BenGurion", - "callsign": "BGN", - "beacon_type": 5, - "hertz": 113500000, - "channel": 82 - }, - "world_16": { - "name": "Almaza", - "callsign": "MXR", - "beacon_type": 4, - "hertz": 116300000, - "channel": 110 - }, - "world_17": { - "name": "Ovda", - "callsign": "OVD", - "beacon_type": 8, - "hertz": 353000, - "channel": 0 - }, - "world_18": { - "name": "Haifa", - "callsign": "HFA", - "beacon_type": 8, - "hertz": 323000, - "channel": 0 - }, - "world_19": { - "name": "Aqaba", - "callsign": "AQ", - "beacon_type": 8, - "hertz": 404000, - "channel": 0 - }, - "world_20": { - "name": "Alexandria", - "callsign": "AXD", - "beacon_type": 8, - "hertz": 403000, - "channel": 0 - }, - "world_21": { - "name": "Baltim", - "callsign": "BLT", - "beacon_type": 3, - "hertz": 116900000, - "channel": 116 - }, - "world_22": { - "name": "Turaif", - "callsign": "TRF", - "beacon_type": 3, - "hertz": 116100000, - "channel": 108 - }, - "world_23": { - "name": "Wejh", - "callsign": "WEJ", - "beacon_type": 5, - "hertz": 113900000, - "channel": 86 - }, - "world_24": { - "name": "Metzada", - "callsign": "MZD", - "beacon_type": 5, - "hertz": 115000000, - "channel": 97 - }, - "world_25": { - "name": "RoshPina", - "callsign": "RPN", - "beacon_type": 8, - "hertz": 243000, - "channel": 0 - }, - "world_26": { - "name": "Hurghada", - "callsign": "HGD", - "beacon_type": 3, - "hertz": 116500000, - "channel": 112 - }, - "world_27": { - "name": "Chekka", - "callsign": "CAK", - "beacon_type": 3, - "hertz": 116200000, - "channel": 109 - }, - "world_28": { - "name": "QueenAlia", - "callsign": "QA", - "beacon_type": 8, - "hertz": 410000, - "channel": 0 - }, - "world_29": { - "name": "October", - "callsign": "OCT", - "beacon_type": 8, - "hertz": 340000, - "channel": 0 - }, - "world_30": { - "name": "PortSaid", - "callsign": "PSD", - "beacon_type": 3, - "hertz": 112700000, - "channel": 74 - }, - "world_31": { - "name": "Alexandria", - "callsign": "NOZ", - "beacon_type": 3, - "hertz": 115900000, - "channel": 106 - }, - "world_32": { - "name": "DeirZzor", - "callsign": "DRZ", - "beacon_type": 8, - "hertz": 295000, - "channel": 0 - }, - "world_33": { - "name": "DeirZzor", - "callsign": "DRZ", - "beacon_type": 3, - "hertz": 117000000, - "channel": 117 - }, - "world_34": { - "name": "Cairo", - "callsign": "ALI", - "beacon_type": 8, - "hertz": 310000, - "channel": 0 - }, - "world_35": { - "name": "Al-Shigar", - "callsign": "ASH", - "beacon_type": 3, - "hertz": 112300000, - "channel": 70 - }, - "world_36": { - "name": "Cairo", - "callsign": "MKT", - "beacon_type": 8, - "hertz": 317000, - "channel": 0 - }, - "world_37": { - "name": "MarsaAlam", - "callsign": "MAK", - "beacon_type": 3, - "hertz": 115500000, - "channel": 102 - }, - "world_38": { - "name": "Taba", - "callsign": "TBA", - "beacon_type": 8, - "hertz": 316000, - "channel": 0 - }, - "world_39": { - "name": "Zofar", - "callsign": "ZFR", - "beacon_type": 3, - "hertz": 115600000, - "channel": 103 - }, - "world_40": { - "name": "Natania", - "callsign": "NAT", - "beacon_type": 5, - "hertz": 112400000, - "channel": 71 - }, - "world_41": { - "name": "Kariatain", - "callsign": "KTN", - "beacon_type": 3, - "hertz": 117700000, - "channel": 124 - }, - "world_42": { - "name": "Herzlia", - "callsign": "HRZ", - "beacon_type": 8, - "hertz": 273000, - "channel": 0 - }, - "world_43": { - "name": "Guriat", - "callsign": "GRY", - "beacon_type": 5, - "hertz": 114700000, - "channel": 94 - }, - "world_44": { - "name": "Gaza", - "callsign": "GZA", - "beacon_type": 3, - "hertz": 113350000, - "channel": 80 - }, - "world_45": { - "name": "Cairo", - "callsign": "CVO", - "beacon_type": 3, - "hertz": 115200000, - "channel": 99 - }, - "world_46": { - "name": "ReneMouawad", - "callsign": "RA", - "beacon_type": 8, - "hertz": 450000, - "channel": 0 - }, - "world_47": { - "name": "Amman", - "callsign": "JYO", - "beacon_type": 8, - "hertz": 391000, - "channel": 0 - }, - "world_48": { - "name": "Aqaba", - "callsign": "AQA", - "beacon_type": 8, - "hertz": 418000, - "channel": 0 - }, - "world_49": { - "name": "Cairo", - "callsign": "CAI", - "beacon_type": 3, - "hertz": 112500000, - "channel": 72 - }, - "world_50": { - "name": "BasselAlAssad", - "callsign": "LTK", - "beacon_type": 8, - "hertz": 414000, - "channel": 0 - }, - "world_51": { - "name": "SharmElSheikh", - "callsign": "SHM", - "beacon_type": 3, - "hertz": 114200000, - "channel": 89 - }, - "world_52": { - "name": "QueenAlia(Locator)", - "callsign": "QL", - "beacon_type": 8, - "hertz": 307000, - "channel": 0 - }, - "world_53": { - "name": "Khaldeh", - "callsign": "KAD", - "beacon_type": 3, - "hertz": 112600000, - "channel": 73 - }, - "world_54": { - "name": "ElDaba", - "callsign": "DBA", - "beacon_type": 3, - "hertz": 115700000, - "channel": 104 - }, - "world_55": { - "name": "InnerBeacon", - "callsign": "D", - "beacon_type": 8, - "hertz": 273000, - "channel": 0 - }, - "world_56": { - "name": "CairoWest", - "callsign": "BLA", - "beacon_type": 4, - "hertz": 116700000, - "channel": 114 - }, - "world_57": { - "name": "Gaza", - "callsign": "RFH", - "beacon_type": 8, - "hertz": 380000, - "channel": 0 - }, - "world_58": { - "name": "Palmyra", - "callsign": "PAL", - "beacon_type": 8, - "hertz": 337000, - "channel": 0 - }, - "world_59": { - "name": "ElKharga", - "callsign": "KHG", - "beacon_type": 3, - "hertz": 113800000, - "channel": 85 - }, - "world_60": { - "name": "Halaifa", - "callsign": "HLF", - "beacon_type": 3, - "hertz": 116700000, - "channel": 114 - }, - "world_61": { - "name": "Aqaba", - "callsign": "AQB", - "beacon_type": 3, - "hertz": 113100000, - "channel": 78 - }, - "world_62": { - "name": "Beirut", - "callsign": "BAB", - "beacon_type": 8, - "hertz": 312000, - "channel": 0 - }, - "world_63": { - "name": "SidiBarrani", - "callsign": "BRN", - "beacon_type": 3, - "hertz": 116200000, - "channel": 109 - }, - "world_64": { - "name": "Luxor", - "callsign": "LXR", - "beacon_type": 3, - "hertz": 114400000, - "channel": 91 - }, - "world_65": { - "name": "Luxor", - "callsign": "LO", - "beacon_type": 8, - "hertz": 364000, - "channel": 0 - }, - "world_66": { - "name": "Tabuk", - "callsign": "TBK", - "beacon_type": 5, - "hertz": 115700000, - "channel": 104 - }, - "world_67": { - "name": "Tanf", - "callsign": "TAN", - "beacon_type": 3, - "hertz": 114000000, - "channel": 87 - }, - "world_68": { - "name": "Qatraneh", - "callsign": "JYT", - "beacon_type": 8, - "hertz": 302000, - "channel": 0 - }, - "world_69": { - "name": "BorgElArab", - "callsign": "DJ", - "beacon_type": 8, - "hertz": 563000, - "channel": 0 - }, - "world_70": { - "name": "Abyad", - "callsign": "ABD", - "beacon_type": 8, - "hertz": 264000, - "channel": 0 - }, - "world_71": { - "name": "Otaebe", - "callsign": "DAL", - "beacon_type": 8, - "hertz": 342000, - "channel": 0 - }, - "world_72": { - "name": "Beer-Sheba", - "callsign": "BSA", - "beacon_type": 5, - "hertz": 114300000, - "channel": 90 - }, - "world_73": { - "name": "Dakhla", - "callsign": "MB", - "beacon_type": 8, - "hertz": 387000, - "channel": 0 - }, - "world_74": { - "name": "Eilot", - "callsign": "LOT", - "beacon_type": 3, - "hertz": 112000000, - "channel": 57 - }, - "world_75": { - "name": "SharmElSheikh", - "callsign": "SKH", - "beacon_type": 8, - "hertz": 335000, - "channel": 0 - }, - "world_76": { - "name": "RoshPina", - "callsign": "ROP", - "beacon_type": 3, - "hertz": 115300000, - "channel": 100 - }, - "world_77": { - "name": "Ovda", - "callsign": "OVD", - "beacon_type": 3, - "hertz": 114100000, - "channel": 88 - }, - "world_78": { - "name": "Qatraneh", - "callsign": "QTR", - "beacon_type": 3, - "hertz": 112900000, - "channel": 76 - }, - "world_79": { - "name": "Fayoum", - "callsign": "FYM", - "beacon_type": 3, - "hertz": 117300000, - "channel": 120 - }, - "airfield2_0": { - "name": "", - "callsign": "WAYR", - "beacon_type": 13, - "hertz": 119700000, - "channel": null - }, - "airfield2_1": { - "name": "", - "callsign": "WAYR", - "beacon_type": 14, - "hertz": 119700000, - "channel": null - }, - "airfield2_2": { - "name": "AbuSuwayr", - "callsign": "ZYT", - "beacon_type": 4, - "hertz": 109200000, - "channel": 29 - }, - "airfield4_0": { - "name": "Ismailiyah", - "callsign": "ISA", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield4_1": { - "name": "Ismailiyah", - "callsign": "ISA", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield14_0": { - "name": "AlMansurah", - "callsign": "MRN", - "beacon_type": 4, - "hertz": 111600000, - "channel": 53 - }, - "airfield3_0": { - "name": "AsSalihiyah", - "callsign": "SAI", - "beacon_type": 13, - "hertz": 110700000, - "channel": null - }, - "airfield3_1": { - "name": "AsSalihiyah", - "callsign": "SAI", - "beacon_type": 14, - "hertz": 110700000, - "channel": null - }, - "airfield3_2": { - "name": "AsSalihiyah", - "callsign": "ASL", - "beacon_type": 4, - "hertz": 111200000, - "channel": 26 - }, - "airfield15_0": { - "name": "AzZaqaziq", - "callsign": "AMB", - "beacon_type": 4, - "hertz": 114700000, - "channel": 94 - }, - "airfield24_0": { - "name": "BenGurion", - "callsign": "BC", - "beacon_type": 13, - "hertz": 110900000, - "channel": null - }, - "airfield24_1": { - "name": "BenGurion", - "callsign": "BC", - "beacon_type": 14, - "hertz": 110900000, - "channel": null - }, - "airfield24_2": { - "name": "BenGurion", - "callsign": "BG", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield24_3": { - "name": "BenGurion", - "callsign": "BN", - "beacon_type": 13, - "hertz": 109700000, - "channel": null - }, - "airfield24_4": { - "name": "BenGurion", - "callsign": "BN", - "beacon_type": 14, - "hertz": 109700000, - "channel": null - }, - "airfield24_5": { - "name": "BenGurion", - "callsign": "BA", - "beacon_type": 14, - "hertz": 108700000, - "channel": null - }, - "airfield24_6": { - "name": "BenGurion", - "callsign": "BA", - "beacon_type": 13, - "hertz": 108700000, - "channel": null - }, - "airfield24_7": { - "name": "BenGurion", - "callsign": "BD", - "beacon_type": 14, - "hertz": 111900000, - "channel": null - }, - "airfield24_8": { - "name": "BenGurion", - "callsign": "BG", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield24_9": { - "name": "BenGurion", - "callsign": "BD", - "beacon_type": 13, - "hertz": 111900000, - "channel": null - }, - "airfield16_0": { - "name": "BilbeisAirBase", - "callsign": "BA", - "beacon_type": 14, - "hertz": 108600000, - "channel": null - }, - "airfield16_1": { - "name": "BilbeisAirBase", - "callsign": "ARF", - "beacon_type": 4, - "hertz": 113900000, - "channel": 86 - }, - "airfield16_2": { - "name": "BilbeisAirBase", - "callsign": "BA", - "beacon_type": 13, - "hertz": 108600000, - "channel": null - }, - "airfield5_0": { - "name": "Melez", - "callsign": "MLZ", - "beacon_type": 3, - "hertz": 110100000, - "channel": 38 - }, - "airfield17_0": { - "name": "CairoInternationalAirport", - "callsign": "IZFL", - "beacon_type": 14, - "hertz": 110900000, - "channel": null - }, - "airfield17_1": { - "name": "CairoInternationalAirport", - "callsign": "IZFCs", - "beacon_type": 14, - "hertz": 109900000, - "channel": null - }, - "airfield17_2": { - "name": "CairoInternationalAirport", - "callsign": "IZFR", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield17_3": { - "name": "CairoInternationalAirport", - "callsign": "IZFR", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield17_4": { - "name": "CairoInternationalAirport", - "callsign": "ITTL", - "beacon_type": 14, - "hertz": 108700000, - "channel": null - }, - "airfield17_5": { - "name": "CairoInternationalAirport", - "callsign": "ITTC", - "beacon_type": 14, - "hertz": 109500000, - "channel": null - }, - "airfield17_6": { - "name": "CairoInternationalAirport", - "callsign": "ITTR", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield17_7": { - "name": "CairoInternationalAirportd", - "callsign": "ITTL", - "beacon_type": 13, - "hertz": 108700000, - "channel": null - }, - "airfield17_8": { - "name": "CairoInternationalAirport", - "callsign": "ITTC", - "beacon_type": 13, - "hertz": 109500000, - "channel": null - }, - "airfield17_9": { - "name": "CairoInternationalAirport", - "callsign": "IZFC", - "beacon_type": 13, - "hertz": 109900000, - "channel": null - }, - "airfield17_10": { - "name": "CairoInternationalAirport", - "callsign": "IZFL", - "beacon_type": 13, - "hertz": 110900000, - "channel": null - }, - "airfield17_11": { - "name": "CairoInternationalAirport", - "callsign": "ITTR", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield18_0": { - "name": "", - "callsign": "SPX", - "beacon_type": 5, - "hertz": 0, - "channel": null - }, - "airfield18_1": { - "name": "CairoWest", - "callsign": "IPSX", - "beacon_type": 14, - "hertz": 111500000, - "channel": null - }, - "airfield18_2": { - "name": "CairoWest", - "callsign": "IPSX", - "beacon_type": 13, - "hertz": 111500000, - "channel": null - }, - "airfield29_0": { - "name": "ElArish", - "callsign": "ARH", - "beacon_type": 3, - "hertz": 113600000, - "channel": 83 - }, - "airfield6_0": { - "name": "Faid", - "callsign": "FAID", - "beacon_type": 13, - "hertz": 110150000, - "channel": 0 - }, - "airfield6_1": { - "name": "Faid", - "callsign": "FAD", - "beacon_type": 14, - "hertz": 110150000, - "channel": 0 - }, - "airfield6_2": { - "name": "Faid", - "callsign": "GIO", - "beacon_type": 4, - "hertz": 117800000, - "channel": 125 - }, - "airfield7_0": { - "name": "Hatzerim", - "callsign": "BRA", - "beacon_type": 5, - "hertz": 114900000, - "channel": 96 - }, - "airfield7_1": { - "name": "Hatzerim", - "callsign": "BRA", - "beacon_type": 13, - "hertz": 111300000, - "channel": null - }, - "airfield7_2": { - "name": "Hatzerim", - "callsign": "BRA", - "beacon_type": 14, - "hertz": 111300000, - "channel": null - }, - "airfield20_1": { - "name": "Hatzor", - "callsign": "HZR", - "beacon_type": 5, - "hertz": 115900000, - "channel": 106 - }, - "airfield20_2": { - "name": "Hatzor", - "callsign": "HZR", - "beacon_type": 14, - "hertz": 108500000, - "channel": null - }, - "airfield20_3": { - "name": "Hatzor", - "callsign": "HZR", - "beacon_type": 13, - "hertz": 108500000, - "channel": null - }, - "airfield19_0": { - "name": "InshasAirbase", - "callsign": "ISH", - "beacon_type": 14, - "hertz": 116900000, - "channel": null - }, - "airfield19_1": { - "name": "InshasAirbase", - "callsign": "IHA", - "beacon_type": 4, - "hertz": 115100000, - "channel": 98 - }, - "airfield19_2": { - "name": "InshasAirbase", - "callsign": "ISH", - "beacon_type": 13, - "hertz": 116900000, - "channel": null - }, - "airfield11_0": { - "name": "Kibrit", - "callsign": "KBR", - "beacon_type": 4, - "hertz": 113700000, - "channel": 55 - }, - "airfield8_0": { - "name": "Nevatim", - "callsign": "NEV", - "beacon_type": 13, - "hertz": 108300000, - "channel": null - }, - "airfield8_1": { - "name": "Nevatim", - "callsign": "NEV", - "beacon_type": 14, - "hertz": 108300000, - "channel": null - }, - "airfield8_2": { - "name": "Nevatim", - "callsign": "NGV", - "beacon_type": 14, - "hertz": 111500000, - "channel": null - }, - "airfield8_3": { - "name": "Nevatim", - "callsign": "NGV", - "beacon_type": 13, - "hertz": 111500000, - "channel": null - }, - "airfield10_0": { - "name": "Ovda", - "callsign": "VA", - "beacon_type": 14, - "hertz": 109700000, - "channel": null - }, - "airfield10_1": { - "name": "Ovda", - "callsign": "OVD", - "beacon_type": 4, - "hertz": 133600000, - "channel": 63 - }, - "airfield10_2": { - "name": "Ovda", - "callsign": "VA", - "beacon_type": 13, - "hertz": 109700000, - "channel": null - }, - "airfield9_0": { - "name": "Ramon", - "callsign": "RMN", - "beacon_type": 13, - "hertz": 110700000, - "channel": null - }, - "airfield9_1": { - "name": "Ramon", - "callsign": "RMN", - "beacon_type": 14, - "hertz": 110700000, - "channel": null - }, - "airfield9_2": { - "name": "Ramon", - "callsign": "RMN", - "beacon_type": 5, - "hertz": 115800000, - "channel": 105 - }, - "airfield23_0": { - "name": "TelNof", - "callsign": "AKR", - "beacon_type": 4, - "hertz": 113700000, - "channel": 87 - }, - "airfield23_1": { - "name": "TelNof", - "callsign": "AKR", - "beacon_type": 13, - "hertz": 109700000, - "channel": null - }, - "airfield23_2": { - "name": "TelNof", - "callsign": "AKR", - "beacon_type": 13, - "hertz": 109100000, - "channel": null - }, - "airfield13_0": { - "name": "WadiAlJandali", - "callsign": "ICTM", - "beacon_type": 13, - "hertz": 109700000, - "channel": null - }, - "airfield13_1": { - "name": "WadiAlJandali", - "callsign": "IKTM", - "beacon_type": 14, - "hertz": 109700000, - "channel": null - }, - "airfield13_2": { - "name": "WadialJandali", - "callsign": "WAJ", - "beacon_type": 4, - "hertz": 114900000, - "channel": 96 - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/syria.json b/resources/dcs/beacons/syria.json deleted file mode 100644 index a1c4ab099..000000000 --- a/resources/dcs/beacons/syria.json +++ /dev/null @@ -1,590 +0,0 @@ -{ - "world_0": { - "name": "BANIAS", - "callsign": "BAN", - "beacon_type": 9, - "hertz": 304000, - "channel": null - }, - "world_1": { - "name": "KAHRAMANMARAS", - "callsign": "KHM", - "beacon_type": 9, - "hertz": 374000, - "channel": null - }, - "world_2": { - "name": "KLEYATE", - "callsign": "RA", - "beacon_type": 9, - "hertz": 450000, - "channel": null - }, - "world_3": { - "name": "KARIATAIN", - "callsign": "KTN", - "beacon_type": 9, - "hertz": 372500, - "channel": null - }, - "world_4": { - "name": "TURAIF", - "callsign": "TRF", - "beacon_type": 3, - "hertz": 116100000, - "channel": null - }, - "world_5": { - "name": "BAYSUR", - "callsign": "BAR", - "beacon_type": 1, - "hertz": 113900000, - "channel": null - }, - "world_6": { - "name": "MARKA", - "callsign": "AMN", - "beacon_type": 3, - "hertz": 116300000, - "channel": null - }, - "world_7": { - "name": "TANF", - "callsign": "TAN", - "beacon_type": 3, - "hertz": 114000000, - "channel": null - }, - "world_8": { - "name": "NATANIA", - "callsign": "NAT", - "beacon_type": 3, - "hertz": 112400000, - "channel": null - }, - "world_9": { - "name": "KAHRAMANMARAS", - "callsign": "KHM", - "beacon_type": 3, - "hertz": 113900000, - "channel": null - }, - "world_10": { - "name": "KARIATAIN", - "callsign": "KTN", - "beacon_type": 3, - "hertz": 117700000, - "channel": null - }, - "world_11": { - "name": "MUT", - "callsign": "MUT", - "beacon_type": 3, - "hertz": 112300000, - "channel": null - }, - "world_12": { - "name": "DHEKELIA", - "callsign": "DKA", - "beacon_type": 9, - "hertz": 343000, - "channel": null - }, - "airfield2_0": { - "name": "", - "callsign": "IADA", - "beacon_type": 13, - "hertz": 108700000, - "channel": null - }, - "airfield2_1": { - "name": "", - "callsign": "IADA", - "beacon_type": 14, - "hertz": 108700000, - "channel": null - }, - "airfield2_2": { - "name": "ADANA", - "callsign": "ADN", - "beacon_type": 10, - "hertz": 395000, - "channel": null - }, - "airfield2_3": { - "name": "ADANA", - "callsign": "ADA", - "beacon_type": 3, - "hertz": 112700000, - "channel": null - }, - "airfield44_0": { - "name": "", - "callsign": "IAK", - "beacon_type": 13, - "hertz": 109700000, - "channel": null - }, - "airfield44_1": { - "name": "", - "callsign": "IAK", - "beacon_type": 14, - "hertz": 109700000, - "channel": null - }, - "airfield44_2": { - "name": "Akrotiri", - "callsign": "AKR", - "beacon_type": 4, - "hertz": 116000000, - "channel": 107 - }, - "airfield44_3": { - "name": "AKROTIRI", - "callsign": "AK", - "beacon_type": 9, - "hertz": 365000, - "channel": null - }, - "airfield6_0": { - "name": "KALDE", - "callsign": "KAD", - "beacon_type": 3, - "hertz": 112600000, - "channel": null - }, - "airfield6_1": { - "name": "", - "callsign": "IBB", - "beacon_type": 14, - "hertz": 110100000, - "channel": null - }, - "airfield6_2": { - "name": "", - "callsign": "IKK", - "beacon_type": 13, - "hertz": 110700000, - "channel": null - }, - "airfield6_3": { - "name": "", - "callsign": "BIL", - "beacon_type": 13, - "hertz": 109500000, - "channel": null - }, - "airfield6_4": { - "name": "", - "callsign": "IBB", - "beacon_type": 13, - "hertz": 110100000, - "channel": null - }, - "airfield6_5": { - "name": "", - "callsign": "BIL", - "beacon_type": 14, - "hertz": 109500000, - "channel": null - }, - "airfield6_6": { - "name": "", - "callsign": "IKK", - "beacon_type": 14, - "hertz": 110700000, - "channel": null - }, - "airfield6_7": { - "name": "BEIRUT", - "callsign": "BOD", - "beacon_type": 10, - "hertz": 351000, - "channel": null - }, - "airfield7_0": { - "name": "", - "callsign": "IDA", - "beacon_type": 14, - "hertz": 109900000, - "channel": null - }, - "airfield7_1": { - "name": "", - "callsign": "IDA", - "beacon_type": 13, - "hertz": 109900000, - "channel": null - }, - "airfield7_2": { - "name": "Damascus", - "callsign": "DAM", - "beacon_type": 3, - "hertz": 116000000, - "channel": null - }, - "airfield7_3": { - "name": "", - "callsign": "DAML", - "beacon_type": 13, - "hertz": 111100000, - "channel": null - }, - "airfield7_4": { - "name": "DAMASCUS", - "callsign": "DAL", - "beacon_type": 10, - "hertz": 342000000, - "channel": null - }, - "airfield7_5": { - "name": "ABYAD", - "callsign": "ABD", - "beacon_type": 9, - "hertz": 264000, - "channel": null - }, - "airfield7_6": { - "name": "", - "callsign": "DAML", - "beacon_type": 14, - "hertz": 111100000, - "channel": null - }, - "airfield42_0": { - "name": "Deir ez-Zor", - "callsign": "DRZ", - "beacon_type": 9, - "hertz": 295000, - "channel": null - }, - "airfield42_1": { - "name": "Deir ez-Zor", - "callsign": "DRZ", - "beacon_type": 3, - "hertz": 117000000, - "channel": null - }, - "airfield49_0": { - "name": "ERCAN", - "callsign": "ECN", - "beacon_type": 3, - "hertz": 117000000, - "channel": null - }, - "airfield49_1": { - "name": "", - "callsign": "IECR", - "beacon_type": 13, - "hertz": 108300000, - "channel": null - }, - "airfield11_0": { - "name": "", - "callsign": "IGNP", - "beacon_type": 13, - "hertz": 109100000, - "channel": null - }, - "airfield11_1": { - "name": "", - "callsign": "IGNP", - "beacon_type": 14, - "hertz": 109100000, - "channel": null - }, - "airfield11_2": { - "name": "GAZIANTEP", - "callsign": "GAZ", - "beacon_type": 9, - "hertz": 432000, - "channel": null - }, - "airfield11_3": { - "name": "GAZIANTEP", - "callsign": "GAZ", - "beacon_type": 3, - "hertz": 116700000, - "channel": null - }, - "airfield41_0": { - "name": "", - "callsign": "IGZP", - "beacon_type": 13, - "hertz": 108500000, - "channel": null - }, - "airfield41_1": { - "name": "ALANYA/GAZIPASA", - "callsign": "GZP", - "beacon_type": 2, - "hertz": 0, - "channel": 89 - }, - "airfield41_2": { - "name": "GAZIPASA/ALANYA", - "callsign": "GZP", - "beacon_type": 9, - "hertz": 316000, - "channel": null - }, - "airfield50_0": { - "name": "FAMAGUSTA_GECITKALE", - "callsign": "GKE", - "beacon_type": 3, - "hertz": 114300000, - "channel": null - }, - "airfield50_1": { - "name": "GECITKALE", - "callsign": "GKE", - "beacon_type": 9, - "hertz": 435000, - "channel": null - }, - "airfield15_0": { - "name": "HATAY", - "callsign": "HTY", - "beacon_type": 3, - "hertz": 112050000, - "channel": null - }, - "airfield15_1": { - "name": "", - "callsign": "IHAT", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield15_2": { - "name": "", - "callsign": "IHAT", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield15_3": { - "name": "HATAY", - "callsign": "HTY", - "beacon_type": 9, - "hertz": 336000, - "channel": null - }, - "airfield16_0": { - "name": "INCIRLIC", - "callsign": "DAN", - "beacon_type": 4, - "hertz": null, - "channel": 21 - }, - "airfield16_1": { - "name": "", - "callsign": "IDAN", - "beacon_type": 13, - "hertz": 109300000, - "channel": null - }, - "airfield16_2": { - "name": "", - "callsign": "IDAN", - "beacon_type": 14, - "hertz": 109300000, - "channel": null - }, - "airfield16_3": { - "name": "", - "callsign": "IDNA", - "beacon_type": 14, - "hertz": 111700000, - "channel": null - }, - "airfield16_4": { - "name": "", - "callsign": "IDNA", - "beacon_type": 13, - "hertz": 111700000, - "channel": null - }, - "airfield47_0": { - "name": "", - "callsign": "ILC", - "beacon_type": 13, - "hertz": 110300000, - "channel": null - }, - "airfield47_1": { - "name": "Larnaca", - "callsign": "LCA", - "beacon_type": 3, - "hertz": 112800000, - "channel": null - }, - "airfield47_2": { - "name": "", - "callsign": "ILC", - "beacon_type": 14, - "hertz": 110300000, - "channel": null - }, - "airfield47_3": { - "name": "Larnaca", - "callsign": "LCA", - "beacon_type": 8, - "hertz": 432000, - "channel": null - }, - "airfield21_0": { - "name": "", - "callsign": "IBA", - "beacon_type": 14, - "hertz": 109100000, - "channel": null - }, - "airfield21_1": { - "name": "", - "callsign": "IBA", - "beacon_type": 13, - "hertz": 109100000, - "channel": null - }, - "airfield21_2": { - "name": "LATAKIA", - "callsign": "LTK", - "beacon_type": 3, - "hertz": 114800000, - "channel": null - }, - "airfield21_3": { - "name": "LATAKIA", - "callsign": "LTK", - "beacon_type": 8, - "hertz": 414000, - "channel": null - }, - "airfield25_0": { - "name": "MEZZEH", - "callsign": "MEZ", - "beacon_type": 9, - "hertz": 358000, - "channel": null - }, - "airfield27_0": { - "name": "ALEPPO", - "callsign": "ALE", - "beacon_type": 9, - "hertz": 396000, - "channel": null - }, - "airfield27_1": { - "name": "ALEPPO", - "callsign": "MER", - "beacon_type": 9, - "hertz": 365000, - "channel": null - }, - "airfield27_2": { - "name": "ALEPPO", - "callsign": "ALE", - "beacon_type": 3, - "hertz": 114500000, - "channel": null - }, - "airfield28_0": { - "name": "PALMYRA", - "callsign": "PLR", - "beacon_type": 9, - "hertz": 363000, - "channel": null - }, - "airfield28_1": { - "name": "PALMYRA", - "callsign": "PAL", - "beacon_type": 9, - "hertz": 337000, - "channel": null - }, - "airfield46_0": { - "name": "Pafos", - "callsign": "PHA", - "beacon_type": 9, - "hertz": 328000, - "channel": null - }, - "airfield46_1": { - "name": "", - "callsign": "IPA", - "beacon_type": 14, - "hertz": 108900000, - "channel": null - }, - "airfield46_2": { - "name": "", - "callsign": "IPA", - "beacon_type": 13, - "hertz": 108900000, - "channel": null - }, - "airfield46_3": { - "name": "Pafos", - "callsign": "IPA", - "beacon_type": 2, - "hertz": 108900000, - "channel": null - }, - "airfield46_4": { - "name": "Pafos", - "callsign": "PHA", - "beacon_type": 3, - "hertz": 117900000, - "channel": null - }, - "airfield46_5": { - "name": "Pafos", - "callsign": "PHA", - "beacon_type": 4, - "hertz": null, - "channel": 79 - }, - "airfield30_0": { - "name": "RAMATDAVID", - "callsign": "RMD", - "beacon_type": 9, - "hertz": 368000, - "channel": null - }, - "airfield30_1": { - "name": "RAMATDAVID", - "callsign": "RMD", - "beacon_type": 5, - "hertz": 113700000, - "channel": 84 - }, - "airfield30_2": { - "name": "", - "callsign": "RMD", - "beacon_type": 13, - "hertz": 111100000, - "channel": null - }, - "airfield30_3": { - "name": "", - "callsign": "RMD", - "beacon_type": 14, - "hertz": 111100000, - "channel": null - }, - "airfield34_0": { - "name": "ROSH-PINA", - "callsign": "ROP", - "beacon_type": 3, - "hertz": 115300000, - "channel": null - }, - "airfield40_0": { - "name": "Cheka", - "callsign": "CAK", - "beacon_type": 3, - "hertz": 116200000, - "channel": null - } -} \ No newline at end of file diff --git a/resources/dcs/beacons/thechannel.json b/resources/dcs/beacons/thechannel.json deleted file mode 100644 index 9e26dfeeb..000000000 --- a/resources/dcs/beacons/thechannel.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/resources/default_logging.yaml b/resources/default_logging.yaml deleted file mode 100644 index 08284a7bc..000000000 --- a/resources/default_logging.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# To override default logging behavior, copy this file to resources/logging.yaml -# and make changes. logging.yaml will take precedence over the default config if -# it exists, but is not tracked by git. -# -# See https://gist.github.com/kingspp/9451566a5555fb022215ca2b7b802f19 and -# https://docs.python.org/3/howto/logging.html for examples. -version: 1 -formatters: - default: - format: "%(asctime)s :: %(name)s :: %(levelname)s :: %(message)s" -handlers: - console: - class: logging.StreamHandler - level: DEBUG - formatter: default - stream: ext://sys.stderr - file: - class: logging.handlers.RotatingFileHandler - level: DEBUG - formatter: default - filename: logs/liberation.log - maxBytes: 5242880 - backupCount: 1 - encoding: utf8 - in_memory: - class: qt_ui.logging_handler.HookableInMemoryHandler - level: DEBUG - formatter: default -root: - level: DEBUG - handlers: [console, file, in_memory] -loggers: - uvicorn.access: - # uvicorn.access logs every HTTP request and its result. It's useful while - # debugging that interface, but otherwise is very noisy, so by default is - # only logged to the file. To include this in the console, add console to - # the list of handlers, or set propagate to true, which will also log to the - # UI's log window. - handlers: [file] - propagate: false - uvicorn.error: - level: INFO - propagate: true diff --git a/resources/default_options.lua b/resources/default_options.lua deleted file mode 100644 index 100e5524c..000000000 --- a/resources/default_options.lua +++ /dev/null @@ -1,221 +0,0 @@ -options = -{ - ["playerName"] = "PRINCE", - ["miscellaneous"] = - { - ["headmove"] = false, - ["TrackIR_external_views"] = false, - ["f5_nearest_ac"] = false, - ["f11_free_camera"] = false, - ["F2_view_effects"] = 1, - ["f10_awacs"] = true, - ["Coordinate_Display"] = "Lat Long", - ["accidental_failures"] = false, - ["autologin"] = true, - ["force_feedback_enabled"] = false, - ["collect_stat"] = true, - ["chat_window_at_start"] = true, - ["synchronize_controls"] = false, - ["show_pilot_body"] = false, - }, -- end of ["miscellaneous"] - ["difficulty"] = - { - ["padlock"] = true, - ["easyRadar"] = false, - ["geffect"] = "reduced", - ["miniHUD"] = false, - ["setGlobal"] = true, - ["birds"] = 0, - ["optionsView"] = "optview_all", - ["permitCrash"] = false, - ["immortal"] = false, - ["cockpitStatusBarAllowed"] = false, - ["cockpitVisualRM"] = false, - ["fuel"] = false, - ["reports"] = true, - ["hideStick"] = false, - ["radio"] = true, - ["map"] = true, - ["spectatorExternalViews"] = false, - ["avionicsLanguage"] = "native", - ["userSnapView"] = false, - ["tips"] = true, - ["userMarks"] = true, - ["units"] = "imperial", - ["externalViews"] = true, - ["iconsTheme"] = "nato", - ["easyFlight"] = false, - ["weapons"] = false, - ["easyCommunication"] = true, - ["labels"] = true, - }, -- end of ["difficulty"] - ["VR"] = - { - ["use_mouse"] = true, - ["hand_controllers"] = true, - ["custom_IPD"] = "63", - ["custom_IPD_enable"] = false, - ["enable"] = true, - ["prefer_built_in_audio"] = true, - ["box_mouse_cursor"] = false, - ["pixel_density"] = 1, - }, -- end of ["VR"] - ["graphics"] = - { - ["rainDroplets"] = 1, - ["preloadRadius"] = 100000, - ["heatBlr"] = 1, - ["anisotropy"] = 4, - ["water"] = 2, - ["motionBlur"] = 0, - ["outputGamma"] = 2, - ["treesVisibility"] = 5000, - ["aspect"] = 1.7777777777778, - ["lights"] = 2, - ["HDR"] = 0, - ["MSAA"] = 0, - ["SSAA"] = 0, - ["height"] = 1080, - ["forestDistanceFactor"] = 0.77, - ["cockpitGI"] = 1, - ["terrainTextures"] = "max", - ["multiMonitorSetup"] = "1camera", - ["shadowTree"] = false, - ["chimneySmokeDensity"] = 0, - ["fullScreen"] = false, - ["disableAero"] = false, - ["DOF"] = 0, - ["clouds"] = 1, - ["flatTerrainShadows"] = 2, - ["width"] = 1920, - ["shadows"] = 2, - ["textures"] = 2, - ["effects"] = 3, - ["SSAO"] = 0, - ["useDeferredShading"] = 1, - ["sync"] = false, - ["LensEffects"] = 3, - ["visibRange"] = "Low", - ["scaleGui"] = false, - ["clutterMaxDistance"] = 750, - ["civTraffic"] = "", - }, -- end of ["graphics"] - ["plugins"] = - { - ["Su-25T"] = - { - ["CPLocalList"] = "default", - }, -- end of ["Su-25T"] - ["M-2000C"] = - { - ["UNI_ALIGNED"] = true, - ["CPLocalList"] = "default", - ["PPA_TOTPAR"] = false, - ["UNI_NODRIFT"] = false, - }, -- end of ["M-2000C"] - ["A-10C"] = - { - ["CPLocalList"] = "default", - }, -- end of ["A-10C"] - ["FC3"] = - { - ["CPLocalList_Su-25"] = "default", - ["CPLocalList_Su-27"] = "default", - ["CPLocalList_A-10A"] = "default", - ["CPLocalList_Su-33"] = "default", - ["CPLocalList_MiG-29S"] = "default", - ["CPLocalList_MiG-29A"] = "default", - ["CPLocalList_J-11A"] = "default", - ["CPLocalList_MiG-29G"] = "default", - ["CPLocalList_F-15C"] = "default", - }, -- end of ["FC3"] - ["F/A-18C"] = - { - ["abDetent"] = true, - ["CPLocalList"] = "default", - }, -- end of ["F/A-18C"] - ["MiG-21Bis"] = - { - ["Pitot"] = false, - ["Engine"] = false, - ["Shake"] = 100, - ["CPLocalList"] = "Default", - ["Reticle"] = false, - ["Freeze"] = false, - }, -- end of ["MiG-21Bis"] - ["AV8BNA"] = - { - ["UNI_ALIGNED"] = false, - ["PPA_TOTPAR"] = false, - ["UNI_NODRIFT"] = false, - }, -- end of ["AV8BNA"] - ["F-5E-3"] = - { - ["JoystickMode"] = 0, - ["SightCamera"] = 0, - ["CPLocalList"] = "default", - ["aiHelper"] = false, - }, -- end of ["F-5E-3"] - ["Mi-8MTV2"] = - { - ["Mi8TrimmingMethod"] = 0, - ["Mi8RudderTrimmer"] = true, - ["Mi8AutopilotAdjustment"] = false, - ["gunCamera"] = 0, - ["Mi8CockpitShake"] = 50, - ["controlHelperMi8"] = false, - ["CPLocalList"] = "default_glass_dirt", - ["Mi8FOV"] = 120, - }, -- end of ["Mi-8MTV2"] - ["AJS37"] = - { - ["CPLocalList"] = "default", - }, -- end of ["AJS37"] - ["TF-51D"] = - { - ["assistance"] = 100, - ["CPLocalList"] = "default", - ["autoRudder"] = false, - }, -- end of ["TF-51D"] - ["UH-1H"] = - { - ["UHRudderTrimmer"] = true, - ["autoPilot"] = true, - ["UH1HCockpitShake"] = 50, - ["CPLocalList"] = "default", - ["weapTooltips"] = false, - ["UHTrimmingMethod"] = 0, - }, -- end of ["UH-1H"] - ["Ka-50"] = - { - ["Ka50TrimmingMethod"] = 0, - ["CPLocalList"] = "default", - ["Ka50RudderTrimmer"] = true, - ["helmetCircleDisplacement"] = 11, - }, -- end of ["Ka-50"] - }, -- end of ["plugins"] - ["format"] = 1, - ["sound"] = - { - ["hear_in_helmet"] = true, - ["headphones"] = 100, - ["cockpit"] = 100, - ["world"] = 5, - ["radioSpeech"] = true, - ["GBreathEffect"] = true, - ["volume"] = 21, - ["headphones_on_external_views"] = true, - ["music"] = 0, - ["subtitles"] = false, - ["gui"] = 100, - }, -- end of ["sound"] - ["views"] = - { - ["cockpit"] = - { - ["mirrors"] = false, - ["reflections"] = false, - ["avionics"] = 1, - }, -- end of ["cockpit"] - }, -- end of ["views"] -} -- end of options diff --git a/resources/doctrines/coldwar.yaml b/resources/doctrines/coldwar.yaml deleted file mode 100644 index 192d38fef..000000000 --- a/resources/doctrines/coldwar.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: coldwar -hold_distance_nm: 15 -push_distance_nm: 10 -join_distance_nm: 10 -max_ingress_distance_nm: 30 -min_ingress_distance_nm: 10 -rendezvous_altitude_ft_msl: 22000 -combat_altitude_ft_msl: 18000 -cap: - duration_minutes: 30 - min_track_length_nm: 12 - max_track_length_nm: 24 - min_distance_from_cp_nm: 8 - max_distance_from_cp_nm: 25 - engagement_range_nm: 35 - min_patrol_altitude_ft_msl: 10000 - max_patrol_altitude_ft_msl: 24000 -cas: - duration_minutes: 30 -sweep: - distance_nm: 40 -ground_unit_procurement_ratios: - Tank: 4 - ATGM: 2 - APC: 3 - IFV: 2 - Artillery: 1 - SHORAD: 2 - Recon: 1 -helicopter: - combat_altitude_ft_agl: 200 - rendezvous_altitude_ft_agl: 1500 - air_assault_nav_altitude_ft_agl: 1500 - diff --git a/resources/doctrines/modern.yaml b/resources/doctrines/modern.yaml deleted file mode 100644 index 2e9137429..000000000 --- a/resources/doctrines/modern.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: modern -hold_distance_nm: 25 -push_distance_nm: 20 -join_distance_nm: 20 -max_ingress_distance_nm: 45 -min_ingress_distance_nm: 10 -rendezvous_altitude_ft_msl: 25000 -combat_altitude_ft_msl: 20000 -cap: - duration_minutes: 30 - min_track_length_nm: 15 - max_track_length_nm: 40 - min_distance_from_cp_nm: 10 - max_distance_from_cp_nm: 40 - engagement_range_nm: 50 - min_patrol_altitude_ft_msl: 15000 - max_patrol_altitude_ft_msl: 33000 -cas: - duration_minutes: 30 -sweep: - distance_nm: 60 -ground_unit_procurement_ratios: - Tank: 3 - ATGM: 2 - APC: 2 - IFV: 3 - Artillery: 1 - SHORAD: 2 - Recon: 1 -helicopter: - combat_altitude_ft_agl: 200 - rendezvous_altitude_ft_agl: 1500 - air_assault_nav_altitude_ft_agl: 1500 diff --git a/resources/doctrines/ww2.yaml b/resources/doctrines/ww2.yaml deleted file mode 100644 index da0415919..000000000 --- a/resources/doctrines/ww2.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: ww2 -hold_distance_nm: 10 -push_distance_nm: 5 -join_distance_nm: 5 -max_ingress_distance_nm: 7 -min_ingress_distance_nm: 5 -rendezvous_altitude_ft_msl: 10000 -combat_altitude_ft_msl: 8000 -cap: - duration_minutes: 30 - min_track_length_nm: 8 - max_track_length_nm: 18 - min_distance_from_cp_nm: 0 - max_distance_from_cp_nm: 5 - engagement_range_nm: 20 - min_patrol_altitude_ft_msl: 4000 - max_patrol_altitude_ft_msl: 15000 -cas: - duration_minutes: 30 -sweep: - distance_nm: 10 -ground_unit_procurement_ratios: - Tank: 3 - ATGM: 3 - APC: 3 - Artillery: 1 - SHORAD: 3 - Recon: 1 -helicopter: - combat_altitude_ft_agl: 200 - rendezvous_altitude_ft_agl: 1500 - air_assault_nav_altitude_ft_agl: 1500 diff --git a/resources/factions/NATO_Desert_Storm.yaml b/resources/factions/NATO_Desert_Storm.yaml deleted file mode 100644 index a7e98c271..000000000 --- a/resources/factions/NATO_Desert_Storm.yaml +++ /dev/null @@ -1,88 +0,0 @@ ---- -country: Combined Joint Task Forces Blue -name: NATO Desert Storm -authors: Hawkmoon -description: -

    A faction to recreate the actual unit lineup during Desert Storm as closely - as possible

    -aircrafts: - - A-10A Thunderbolt II - - AH-64A Apache - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - F-117A Nighthawk - - F-14A Tomcat (Block 135-GR Late) - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - F/A-18C Hornet (Lot 20) - - Mirage 2000C - - OH-58D Kiowa Warrior - - S-3B Viking - - SA 342L Gazelle - - SA 342M Gazelle - - SA 342M Gazelle Mistral - - Tornado IDS - - UH-1H Iroquois -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker - - S-3B Tanker -frontline_units: - - FV4034 Challenger 2 - - FV510 Warrior - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - M1126 Stryker ICV (M2 HMG) - - M1128 Stryker Mobile Gun System - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley - - M60A3 "Patton" - - TPz Fuchs - - VAB Mephisto -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Rapier - - Roland - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M163 Vulcan Air Defense System - - M1097 Heavy HMMWV Avenger - - M48 Chaparral -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-4 Nassau -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/NATO_OIF.yaml b/resources/factions/NATO_OIF.yaml deleted file mode 100644 index 9331fff96..000000000 --- a/resources/factions/NATO_OIF.yaml +++ /dev/null @@ -1,91 +0,0 @@ ---- -country: Combined Joint Task Forces Blue -name: NATO OIF -authors: Fuzzle -description: -

    A more modern NATO mixed faction reflecting the units involved in Operation - Iraqi Freedom.

    -aircrafts: - - A-10C Thunderbolt II (Suite 3) - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - F-117A Nighthawk - - F-14A Tomcat (Block 135-GR Late) - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-22A Raptor - - F/A-18C Hornet (Lot 20) - - Mirage 2000C - - OH-58D Kiowa Warrior - - S-3B Viking - - SA 342L Gazelle - - SA 342M Gazelle - - SA 342M Gazelle Mistral - - Tornado GR4 - - UH-1H Iroquois - - UH-60A - - UH-60L -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-130J - - KC-135 Stratotanker - - S-3B Tanker -frontline_units: - - FV4034 Challenger 2 - - FV510 Warrior - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley - - M6 Linebacker - - Marder 1A3 - - VAB Mephisto -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Rapier - - Roland - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M163 Vulcan Air Defense System - - M1097 Heavy HMMWV Avenger - - M48 Chaparral -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-4 Nassau -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/allies_1940.yaml b/resources/factions/allies_1940.yaml deleted file mode 100644 index c683385ad..000000000 --- a/resources/factions/allies_1940.yaml +++ /dev/null @@ -1,41 +0,0 @@ ---- -country: UK -name: Allies 1940 -authors: Khopa -description: -

    A generic WW2 ally factions for 1940 Battle of France or Battle of - England.

    -aircrafts: - - Boston Mk.III - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) - - MosquitoFBMkVI -frontline_units: - - A17 Light Tank Mk VII Tetrarch - - A22 Infantry Tank MK IV Churchill VII - - Daimler Armoured Car Mk I - - M2A1 Half-Track - - QF 3.7-inch AA Gun - - QF 40 mm Mark III -artillery_units: [] -logistics_units: - - Truck Bedford - - Truck GMC "Jimmy" 6x6 Truck -infantry_units: - - Infantry M1 Garand - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Ally Flak - - WW2LST -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II diff --git a/resources/factions/allies_1944.yaml b/resources/factions/allies_1944.yaml deleted file mode 100644 index 6015e84e5..000000000 --- a/resources/factions/allies_1944.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -country: USA -name: Allies 1944 -authors: Khopa -description:

    A generic WW2 ally factions, with all their WW2 units.

    -aircrafts: - - A-20G Havoc - - C-47 Skytrain - - B-17G Flying Fortress - - P-47D-30 Thunderbolt (Early) - - P-47D-30 Thunderbolt (Late) - - P-47D-40 Thunderbolt - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) - - MosquitoFBMkVI -frontline_units: - - A17 Light Tank Mk VII Tetrarch - - A22 Infantry Tank MK IV Churchill VII - - A27L Cruiser Tank MK VIII Centaur IV - - A27M Cruiser Tank MK VIII Cromwell IV - - Bofors 40 mm Gun - - Daimler Armoured Car Mk I - - M10 3-inch Gun Motor Carriage - - M2A1 Half-Track - - M4A2(75) Sherman - - M4A4 Sherman Firefly - - M8 Greyhound Light Armored Car - - QF 3.7-inch AA Gun -artillery_units: - - M12 Gun Motor Carriage - - FH M2A1 105mm -logistics_units: - - Truck Bedford - - Truck GMC "Jimmy" 6x6 Truck -infantry_units: - - Infantry M1 Garand - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Ally Flak - - WW2LST -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II diff --git a/resources/factions/allies_1944_free.yaml b/resources/factions/allies_1944_free.yaml deleted file mode 100644 index d7d594317..000000000 --- a/resources/factions/allies_1944_free.yaml +++ /dev/null @@ -1,37 +0,0 @@ ---- -country: USA -name: Allies 1944 (Free) -authors: Khopa -description: -

    A generic WW2 ally faction that does not requires the paid WW2 asset - pack.

    -aircrafts: - - A-20G Havoc - - P-47D-30 Thunderbolt (Early) - - P-47D-30 Thunderbolt (Late) - - P-47D-40 Thunderbolt - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) - - MosquitoFBMkVI -frontline_units: - - Bofors 40 mm Gun - - M2A1 Half-Track - - M4A2(75) Sherman -artillery_units: [] -logistics_units: - - Truck Bedford -infantry_units: - - Paratrooper AKS -air_defense_units: - - Bofors 40 mm Gun -preset_groups: [] -naval_units: [] -missiles: [] -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2free diff --git a/resources/factions/argentina_1982.yaml b/resources/factions/argentina_1982.yaml deleted file mode 100644 index 63211da77..000000000 --- a/resources/factions/argentina_1982.yaml +++ /dev/null @@ -1,40 +0,0 @@ ---- -country: Argentina -name: Argentina 1982 -authors: Nosaj -description:

    Starter Argentina faction during falklands war for testing the ARA Veinticinco de Mayo. Using the Castle Class as a stand-in for the rest of the Argentine Navy.

    -locales: - - es_ES -aircrafts: - - A-4E Skyhawk - - C-130 - - C-130J-30 Super Hercules - - CH-47D - - MB-339A - - UH-1H Iroquois -awacs: [] -tankers: - - KC-130 -frontline_units: - - AAVP-7A1 'Amtrac' - - Scout LC with DSHK 12.7mm - - Scout LC with KORD 12.7mm -artillery_units: - - MLRS LC with B8M1 80mm -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - Mortar 2B11 120mm -preset_groups: - - Roland -naval_units: - - ARA Veinticinco de Mayo - - Castle Class -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -requirements: {} -carrier_names: - - ARA Veinticinco de Mayo diff --git a/resources/factions/australia_2005.yaml b/resources/factions/australia_2005.yaml deleted file mode 100644 index b8d0e38e6..000000000 --- a/resources/factions/australia_2005.yaml +++ /dev/null @@ -1,53 +0,0 @@ -country: Australia -name: Australia 2005 -authors: 'Khopa, SpaceEnthusiast' -description: >- -

    The Australian army in 2005.

    Some units might not be accurate, but - were picked to represent at best this army.

    -aircrafts: - - AH-1W SuperCobra - - C-130J-30 Super Hercules - - F/A-18C Hornet (Lot 20) - - F/A-18F Super Hornet - - SH-60B Seahawk - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - LAV-25 - - Leopard 1A3 - - M113 - - M1A2 Abrams -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Rapier -naval_units: - - DDG Arleigh Burke IIa - - LHA-1 Tarawa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) -requirements: - C-130J-30 Super Hercules Mod by Anubis: 'https://forums.eagle.ru/topic/252075-dcs-super-hercules-mod-by-anubis/' -carrier_names: [] -helicopter_carrier_names: - - HMAS Canberra - - HMAS Adelaide -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - F/A-18C Hornet (Lot 20): - - Australian 75th Squadron - - Australian 77th Squadron -unrestricted_satnav: true diff --git a/resources/factions/australia_2009.yaml b/resources/factions/australia_2009.yaml deleted file mode 100644 index da3c55891..000000000 --- a/resources/factions/australia_2009.yaml +++ /dev/null @@ -1,49 +0,0 @@ -country: Australia -name: Australia 2009 -authors: 'Khopa, SpaceEnthusiast, Chilli' -description: >- -

    The Australian army in 2009.

    Some units might not be accurate, but - were picked to represent at best this army.

    -aircrafts: - - AH-1W SuperCobra - - C-130J-30 Super Hercules - - F/A-18F Super Hornet - - EA-18G Growler - - SH-60B Seahawk - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - LAV-25 - - Leopard 1A3 - - M113 - - M1A2 Abrams -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Rapier -naval_units: - - DDG Arleigh Burke IIa - - LHA-1 Tarawa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) -requirements: - C-130J-30 Super Hercules Mod by Anubis: 'https://forums.eagle.ru/topic/252075-dcs-super-hercules-mod-by-anubis/' -carrier_names: [] -helicopter_carrier_names: - - HMAS Canberra - - HMAS Adelaide -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/bluefor_coldwar.yaml b/resources/factions/bluefor_coldwar.yaml deleted file mode 100644 index d03d339e5..000000000 --- a/resources/factions/bluefor_coldwar.yaml +++ /dev/null @@ -1,70 +0,0 @@ ---- -country: Combined Joint Task Forces Blue -name: Bluefor Coldwar -authors: Khopa -description:

    A generic bluefor coldwar faction. (With the A-4E-C mod)

    -aircrafts: - - A-10A Thunderbolt II - - A-4E Skyhawk - - AJS-37 Viggen - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - F-14A Tomcat (Block 135-GR Late) - - F-14B Tomcat - - F-4E Phantom II - - F-5E Tiger II - - Mirage-F1B - - Mirage-F1BE - - Mirage-F1CE - - Mirage-F1C-200 - - Mirage-F1EE - - SA 342L Gazelle - - SA 342M Gazelle - - UH-1H Iroquois -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M48 Chaparral - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -missiles: [] -preset_groups: - - Hawk - - Cold-War-Flak -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: - Community A-4E: https://heclak.github.io/community-a4e-c/ -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -doctrine: coldwar diff --git a/resources/factions/bluefor_modern.yaml b/resources/factions/bluefor_modern.yaml deleted file mode 100644 index b20221cd0..000000000 --- a/resources/factions/bluefor_modern.yaml +++ /dev/null @@ -1,137 +0,0 @@ ---- -country: Combined Joint Task Forces Blue -name: Bluefor Modern -authors: Khopa -description: -

    A generic bluefor modern faction. This also includes many redfor units and - is meant to be a faction that has access to most modern flyable modules.

    -aircrafts: - - A-10A Thunderbolt II - - A-10C Thunderbolt II (Suite 3) - - A-10C Thunderbolt II (Suite 7) - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - AJS-37 Viggen - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - C-17A - - CH-47D - - CH-53E - - F-117A Nighthawk - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-22A Raptor - - F-5E Tiger II - - F/A-18C Hornet (Lot 20) - - J-11A Flanker-L - - JF-17 Thunder - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - Mirage 2000C - - Mirage-F1B - - Mirage-F1BE - - Mirage-F1CE - - Mirage-F1C-200 - - Mirage-F1CT - - Mirage-F1EE - - Mirage-F1M-CE - - Mirage-F1M-EE - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-29S Fulcrum-C - - SA 342L Gazelle - - SA 342M Gazelle - - Su-25T Frogfoot - - Su-27 Flanker-B - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois - - UH-60A - - UH-60L -awacs: - - E-2D Advanced Hawkeye - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker - - KC-135 Stratotanker MPRS - - S-3B Tanker -frontline_units: - - LAV-25 - - Leopard 2 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley - - M6 Linebacker - - Marder 1A3 - - Merkava Mk IV - - VAB Mephisto -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Hawk - - Patriot - - NASAMS AIM-120C -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger - - M6 Linebacker - - Centurion C-RAM LPWS -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true -liveries_overrides: - J-11A Flanker-L: - - USN Aggressor VFC-13 'Ferris' (Fictional) - JF-17 Thunder: - - "'Chips' Camo for Blue Side (Fictional)" - Ka-50 Hokum: - - georgia camo - Ka-50 Hokum (Blackshark 3): - - Ka-50_black_neutral - Mi-8MTV2 Hip: - - Ukraine - Mi-24P Hind-F: - - Ukrainian Army Aviation - MiG-29S Fulcrum-C: - - Air Force Ukraine Standard - Su-25T Frogfoot: - - af standard 101 - Su-27 Flanker-B: - - Air Force Ukraine Standard diff --git a/resources/factions/canada_2005.yaml b/resources/factions/canada_2005.yaml deleted file mode 100644 index 7830e7705..000000000 --- a/resources/factions/canada_2005.yaml +++ /dev/null @@ -1,55 +0,0 @@ ---- -country: Canada -name: Canada 2005 -authors: Khopa, SpaceEnthusiast -description:

    Canada in the 2000s, an F/A-18C Hornet focused faction.

    -locales: - - en_US - - fr_CA -aircrafts: - - AH-1W SuperCobra - - C-130J-30 Super Hercules - - CF-188 Hornet - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - LAV-25 - - Leopard 1A3 - - Leopard 2 - - Leopard 2A4 - - M1097 Heavy HMMWV Avenger - - M113 -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger -requirements: - C-130J-30 Super Hercules Mod by Anubis: https://forums.eagle.ru/topic/252075-dcs-super-hercules-mod-by-anubis/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - CF-188 Hornet: - - Canada 409th Squadron - - Canada 425th Squadron - C-130J-30 Super Hercules: - - Royal Canadian AF CC-130J -unrestricted_satnav: true diff --git a/resources/factions/china_2010.yaml b/resources/factions/china_2010.yaml deleted file mode 100644 index f203cc911..000000000 --- a/resources/factions/china_2010.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -country: China -name: China 2010 -authors: Khopa -description:

    China in the late 2000s, early 2010s.

    -locales: - - zh_CN -aircrafts: - - FC-1 Fierce Dragon - - IL-76MD - - J-11A Flanker-L - - J-15 Flanker X-2 - - J-7B - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - Su-30MKK Flanker-G - - H-6J Badger -awacs: - - KJ-2000 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - HQ-7 Launcher - - MT Type 59 - - Type 04A (ZBD-04A) - - Type 96B (ZTZ-96B) -artillery_units: - - 2S9 Nona-S - - BM-30 Smerch (9M55K5 HE Rockets) - - PLZ-05 -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-2/S-75 - - HQ-2 - - SA-6 - - SA-11 - - HQ-7 - - SA-10/S-300PS - - SA-20B/S-300PMU-2 - - Silkworm - - Chinese Navy -naval_units: - - Type 052B Destroyer - - Type 052C Destroyer - - Type 054A Frigate - - Type 093 Attack Submarine - - CV 1143.5 Admiral Kuznetsov - - Type 071 Amphibious Transport Dock -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -carrier_names: - - 001 Liaoning - - 002 Shandong -helicopter_carrier_names: - - Kunlun Shan - - Jinggang Shan - - Changbai Shan - - Yimeng Shan - - Longhu Shan - - Wuzhi Shan - - Wudang Shan -requirements: {} -has_jtac: true -jtac_unit: WingLoong-I diff --git a/resources/factions/dprk_1950_fictional.yaml b/resources/factions/dprk_1950_fictional.yaml deleted file mode 100644 index 88520adf6..000000000 --- a/resources/factions/dprk_1950_fictional.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -country: North Korea -name: North Korea 1950, fictional -authors: BenBenBeartrax -description: -

    Fictional DPRK (North Korea) army around 1955, during the Korean War, with - some WW2 planes added in place of their post-war counterparts.

    -aircrafts: - - "Bf 109 K-4 Kurf\xFCrst" - - Fw 190 A-8 Anton - - Fw 190 D-9 Dora - - I-16 Ishak - - MiG-15bis Fagot -awacs: [] -tankers: [] -frontline_units: - - 8.8 cm Flak 18 - - BRDM-2 - - Grad MRL FDDM (FC) - - MT-LB - - T-55A - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG -missiles: [] -air_defense_units: [] -preset_groups: - - Cold-War-Flak - - Flak -naval_units: [] -helicopter_carrier_names: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -has_jtac: false -doctrine: ww2 -cargo_ship: LST Mk.II diff --git a/resources/factions/egypt_2000.yaml b/resources/factions/egypt_2000.yaml deleted file mode 100644 index c8291898a..000000000 --- a/resources/factions/egypt_2000.yaml +++ /dev/null @@ -1,84 +0,0 @@ ---- -country: Egypt -name: Egypt 2000 -authors: Starfire -description:

    Egyptian military in the 21st century.

    -locales: - - ar_SA -aircrafts: - - MiG-29S Fulcrum-C - - MiG-21bis Fishbed-N - - Mirage 2000C - - F-4E Phantom II - - F-16CM Fighting Falcon (Block 50) - - IL-76MD - - C-130 - - C-130J-30 Super Hercules - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - SA 342L Gazelle - - SA 342M Gazelle - - CH-47D - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip -awacs: - - E-2C Hawkeye -frontline_units: - - M1A2 Abrams - - M60A3 "Patton" - - T-90A - - T-55A - - BMP-1 - - M113 - - BTR-80 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - ZSU-23-4 Shilka - - M163 Vulcan Air Defense System -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck Ural-375 - - Truck Ural-4320T - - Truck GAZ-66 -infantry_units: - - Infantry RPG - - Infantry AK-74 Rus - - MANPADS SA-18 Igla "Grouse" - - MANPADS Stinger - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-2/S-75 - - SA-6 - - SA-17 - - SA-10/S-300PS - - SA-23/S-300VM - - Patriot - - Hawk -naval_units: - - FFG Oliver Hazard Perry - - Corvette 1241.1 Molniya - - FAC La Combattante IIa -missiles: - - SSM SS-1C Scud-B -air_defense_units: - - EWR AN/FPS-117 Radar - - EWR 55G6 - - M1097 Heavy HMMWV Avenger - - M48 Chaparral - - M163 Vulcan Air Defense System - - SA-9 Strela - - SA-15 Tor - - ZSU-23-4 Shilka - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-57-2 'Sparka' -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/france_1985.yaml b/resources/factions/france_1985.yaml deleted file mode 100644 index 7019c169a..000000000 --- a/resources/factions/france_1985.yaml +++ /dev/null @@ -1,66 +0,0 @@ ---- -country: France -name: France 1985 -authors: Colonel Panic -description: -

    France 1985. Frenchpack 4.6+ mod is recommended to enable most of - the ground units of this faction available.

    -locales: - - fr_FR -doctrine: coldwar -aircrafts: - - C-130 - - Mirage 2000C - - Mirage-F1B - - Mirage-F1CE - - Mirage-F1C-200 - - SA 342L Gazelle - - SA 342M Gazelle - - SA 342M Gazelle Mistral -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - AMX.30B2 - - "Leclerc S\xE9ries 2" - - Pamela - - Panhard - - Roland 2 (Marder Chassis) - - VAB .50 - - VAB Mephisto - - VAB T20/13 - - VBL .50 - - VBL AANF1 - - AMX-13 75mm - - AMX-13 90mm -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -air_defense_units: [] -preset_groups: - - Hawk - - Roland -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa -missiles: [] -requirements: - frenchpack V3.5: https://forums.eagle.ru/showthread.php?t=279974 -carrier_names: - - R91 Charles de Gaulle -helicopter_carrier_names: - - R97 Jeanne d'Arc - - L9013 Mistral - - L9014 Tonerre - - L9015 Dixmude -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/france_1995.yaml b/resources/factions/france_1995.yaml deleted file mode 100644 index 435cc6a30..000000000 --- a/resources/factions/france_1995.yaml +++ /dev/null @@ -1,67 +0,0 @@ ---- -country: France -name: France 1995 -authors: Khopa -description: -

    France in the late 90s before Rafale introduction. A Mirage-2000 centric - faction choice. Frenchpack 4.6+ mod is recommended to enable most of the ground - units of this faction available.

    -locales: - - fr_FR -aircrafts: - - C-130 - - Mirage 2000-5 - - Mirage 2000C - - Mirage-F1B - - Mirage-F1CE - - Mirage-F1C-200 - - Mirage-F1CT - - SA 342L Gazelle - - SA 342M Gazelle - - SA 342M Gazelle Mistral -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - AMX-10 RCR - - AMX-13 90mm - - AMX.30B2 - - "Leclerc S\xE9ries 2" - - Leclerc_XXI - - Pamela - - Panhard - - Roland 2 (Marder Chassis) - - VAB .50 - - VAB Mephisto - - VAB T20/13 - - VBL .50 - - VBL AANF1 -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Hawk - - Roland -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) -requirements: {} -carrier_names: [] -helicopter_carrier_names: - - Jeanne d'Arc -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/france_2005.yaml b/resources/factions/france_2005.yaml deleted file mode 100644 index 6b80d9316..000000000 --- a/resources/factions/france_2005.yaml +++ /dev/null @@ -1,69 +0,0 @@ ---- -country: France -name: France 2005 -authors: HerrTom -description: -

    France 2005. Frenchpack 4.6+ mod is recommended to enable most of - the ground units of this faction available.

    -locales: - - fr_FR -aircrafts: - - C-130 - - Mirage 2000-5 - - Mirage 2000C - - Mirage-F1B - - Mirage-F1CE - - Mirage-F1C-200 - - Mirage-F1CT - - SA 342L Gazelle - - SA 342M Gazelle - - SA 342M Gazelle Mistral -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - AMX-10RCR SEPAR - - "Leclerc S\xE9ries 2" - - Leclerc_XXI - - Pamela - - Panhard - - Roland 2 (Marder Chassis) - - VAB .50 - - VAB Mephisto - - VAB T20/13 - - VBL .50 - - VBL AANF1 - - VBCI -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -air_defense_units: [] -preset_groups: - - Hawk - - Roland -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -requirements: - frenchpack V3.5: https://forums.eagle.ru/showthread.php?t=279974 -carrier_names: - - R91 Charles de Gaulle -helicopter_carrier_names: - - R97 Jeanne d'Arc - - L9013 Mistral - - L9014 Tonerre - - L9015 Dixmude -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/gdr_1985.yaml b/resources/factions/gdr_1985.yaml deleted file mode 100644 index e08af7303..000000000 --- a/resources/factions/gdr_1985.yaml +++ /dev/null @@ -1,59 +0,0 @@ ---- -country: GDR -name: German Democratic Republic 1985 -authors: Colonel Panic -description:

    The German Democratic Republic in 1985.

    -locales: - - de_DE -doctrine: coldwar -aircrafts: - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - Su-17M4 Fitter-K -awacs: [] -tankers: [] -frontline_units: - - BMP-1 - - BMP-2 - - BRDM-2 - - MT-LB - - T-55A - - T-72B with Kontakt-1 ERA -artillery_units: - - 2S1 Gvozdika - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - Mortar 2B11 120mm -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - Cold-War-Flak -naval_units: - - CG Ticonderoga -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZSU-23-4 Shilka -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: Mi-8MTV2 Hip diff --git a/resources/factions/georgia_2008.yaml b/resources/factions/georgia_2008.yaml deleted file mode 100644 index 74ab8b186..000000000 --- a/resources/factions/georgia_2008.yaml +++ /dev/null @@ -1,51 +0,0 @@ ---- -country: Georgia -name: Georgia 2008 -authors: HerrTom -description: -

    A faction that represents Georgia during the South Ossetian War. They - will have a lot more aircraft than historically, and no real A2A capability.

    -aircrafts: - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - Su-25 Frogfoot - - UH-1H Iroquois -frontline_units: - - BMP-1 - - BMP-2 - - BTR-80 - - Cobra - - MT-LB - - SA-13 Gopher (9K35 Strela-10M3) - - T-55A - - T-72B with Kontakt-1 ERA -artillery_units: - - 2S1 Gvozdika - - 2S3 Akatsiya - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -air_defense_units: - - SAM SA-8 Osa "Gecko" TEL - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -preset_groups: - - SA-3/S-125 - - SA-6 - - SA-11 -naval_units: - - FAC La Combattante IIa -requirements: {} -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/germany_1940.yaml b/resources/factions/germany_1940.yaml deleted file mode 100644 index b38cc40af..000000000 --- a/resources/factions/germany_1940.yaml +++ /dev/null @@ -1,40 +0,0 @@ ---- -country: Third Reich -name: Germany 1940 -authors: Khopa -description: -

    Germany 1940, Early german faction for Battle of France, or Battle of - England.

    -locales: - - de_DE -aircrafts: - - "Bf 109 K-4 Kurf\xFCrst" - - Ju 88 A-4 -frontline_units: - - 8.8 cm Flak 18 - - Panzerkampfwagen IV Ausf. H - - Sd.Kfz.234/2 Puma - - Sd.Kfz.251 "Hanomag" -artillery_units: [] -logistics_units: - - LUV Kettenrad - - LUV Kubelwagen 82 - - Sd.Kfz.7 Tractor - - Truck Opel Blitz -infantry_units: - - Infantry Mauser 98 -missiles: [] -air_defense_units: [] -preset_groups: - - Flak -naval_units: - - Boat Schnellboot type S130 - - U-boat VIIC U-flak -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2germany -cargo_ship: LST Mk.II diff --git a/resources/factions/germany_1942.yaml b/resources/factions/germany_1942.yaml deleted file mode 100644 index d7b66e5db..000000000 --- a/resources/factions/germany_1942.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -country: Third Reich -name: Germany 1942 -authors: Khopa -description: -

    Germany 1942, is a faction that does not use the late war german units such - as the Tiger tank, so it's a bit easier to perform CAS against them.

    -locales: - - de_DE -aircrafts: - - "Bf 109 K-4 Kurf\xFCrst" - - Ju 88 A-4 -frontline_units: - - 8.8 cm Flak 18 - - Jagdpanzer IV - - Panzerkampfwagen IV Ausf. H - - Sd.Kfz.234/2 Puma - - Sd.Kfz.251 "Hanomag" - - "Sturmpanzer IV Brummb\xE4r" -artillery_units: [] -logistics_units: - - LUV Kettenrad - - LUV Kubelwagen 82 - - Sd.Kfz.7 Tractor - - Truck Opel Blitz -infantry_units: - - Infantry Mauser 98 -missiles: [] -air_defense_units: [] -preset_groups: - - Flak - - Freya -naval_units: - - Boat Schnellboot type S130 - - U-boat VIIC U-flak -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2germany -cargo_ship: LST Mk.II diff --git a/resources/factions/germany_1944.yaml b/resources/factions/germany_1944.yaml deleted file mode 100644 index e68ae4b6d..000000000 --- a/resources/factions/germany_1944.yaml +++ /dev/null @@ -1,53 +0,0 @@ ---- -country: Third Reich -name: Germany 1944 -authors: Khopa -description: -

    Late war Germany with access to all the late-war ground units such as the - Tiger and Tiger II tanks.

    -locales: - - de_DE -aircrafts: - - "Bf 109 K-4 Kurf\xFCrst" - - Fw 190 A-8 Anton - - Fw 190 D-9 Dora - - Ju 88 A-4 -frontline_units: - - 8.8 cm Flak 18 - - 8.8 cm Flak 41 - - Jagdpanther G1 - - Jagdpanzer IV - - Panzerkampfwagen IV Ausf. H - - Panzerkampfwagen Tiger Ausf. B Tiger II - - Panzerkampfwagen V Panther Ausf. G - - Panzerkampfwagen VI Tiger Ausf. E - - Sd.Kfz.184 Elefant - - Sd.Kfz.234/2 Puma - - Sd.Kfz.251 "Hanomag" - - "Sturmgesch\xFCtz III Ausf. G" - - "Sturmgesch\xFCtz IV" - - "Sturmpanzer IV Brummb\xE4r" -artillery_units: [] -logistics_units: - - LUV Kettenrad - - LUV Kubelwagen 82 - - Sd.Kfz.7 Tractor - - Truck Opel Blitz -infantry_units: - - Infantry Mauser 98 -air_defense_units: [] -preset_groups: - - Flak - - Freya -naval_units: - - Boat Schnellboot type S130 -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -missiles: - - V-1 Launch Ramp -has_jtac: false -doctrine: ww2 -building_set: ww2germany -cargo_ship: LST Mk.II diff --git a/resources/factions/germany_1944_free.yaml b/resources/factions/germany_1944_free.yaml deleted file mode 100644 index bc32c57f5..000000000 --- a/resources/factions/germany_1944_free.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -country: Third Reich -name: Germany 1944 (Free) -authors: Khopa -description:

    WW2 germany faction that does not require the WW2 asset pack.

    -locales: - - de_DE -aircrafts: - - "Bf 109 K-4 Kurf\xFCrst" - - Fw 190 A-8 Anton - - Fw 190 D-9 Dora -frontline_units: - - Truck Opel Blitz - - Panzerkampfwagen IV Ausf. H - - Sd.Kfz.251 "Hanomag" -artillery_units: [] -logistics_units: - - Truck Opel Blitz -infantry_units: - - Infantry AK-74 Rus -air_defense_units: - - 8.8 cm Flak 18 -preset_groups: [] -naval_units: [] -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -missiles: [] -has_jtac: false -doctrine: ww2 -building_set: ww2free diff --git a/resources/factions/germany_1990.yaml b/resources/factions/germany_1990.yaml deleted file mode 100644 index ba2ead7e5..000000000 --- a/resources/factions/germany_1990.yaml +++ /dev/null @@ -1,51 +0,0 @@ ---- -country: Germany -name: Germany 1990 -authors: Khopa -description:

    1990s reunited Germany.

    -locales: - - de_DE -aircrafts: - - C-130 - - F-4F Phantom II - - MiG-29G Fulcrum-A - - SA 342L Gazelle - - SA 342M Gazelle - - Tornado IDS - - UH-1D Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Flakpanzer Gepard - - Leopard 1A3 - - Leopard 2A4 - - Marder 1A3 - - TPz Fuchs -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Hawk - - Roland - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - FAC La Combattante IIa - - CG Ticonderoga -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - Flakpanzer Gepard -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/greece_2005.yaml b/resources/factions/greece_2005.yaml deleted file mode 100644 index 54e833fd6..000000000 --- a/resources/factions/greece_2005.yaml +++ /dev/null @@ -1,53 +0,0 @@ ---- -country: Greece -name: Greece 2005 -authors: Malakhit -description:

    Hellenic army in the mid/late 2000s.

    -locales: - - el_GR -aircrafts: - - AH-64A Apache - - C-130 - - C-130J-30 Super Hercules - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - Mirage 2000-5 - - Mirage 2000C - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 -frontline_units: - - BMP-1 - - Leopard 1A3 - - Leopard 2A4 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M113 - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -missiles: [] -preset_groups: - - Hawk - - Patriot - - SA-10/S-300PS - - SA-20/S-300PMU-1 -naval_units: - - FAC La Combattante IIa -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-8 Osa "Gecko" TEL - - SA-15 Tor - - AAA ZU-23 Closed Emplacement -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/india_2010.yaml b/resources/factions/india_2010.yaml deleted file mode 100644 index 294d1f178..000000000 --- a/resources/factions/india_2010.yaml +++ /dev/null @@ -1,64 +0,0 @@ ---- -country: India -name: India 2010 -authors: Khopa -description:

    Indian faction in the late 2000s.

    -locales: - - en_IN -aircrafts: - - AH-64A Apache - - IL-76MD - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-27K Flogger-J2 - - MiG-29S Fulcrum-C - - Mirage 2000-5 - - Mirage 2000C - - Su-30 Flanker-C -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-2 - - SA-19 Grison (2K22 Tunguska) - - T-72B with Kontakt-1 ERA - - T-90A -artillery_units: - - 2S19 Msta-S - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry M4 - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-3/S-125 - - SA-6 - - SA-11 - - SA-10/S-300PS -naval_units: - - FFG Oliver Hazard Perry - - Corvette 1241.1 Molniya - - Frigate 1135M Rezky - - CV 1143.5 Admiral Kuznetsov -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: - - INS Vikramaditya -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/insurgents.yaml b/resources/factions/insurgents.yaml deleted file mode 100644 index 5511b9e1c..000000000 --- a/resources/factions/insurgents.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -country: Insurgents -name: Insurgents -authors: Khopa -description:

    Insurgents faction.

    -aircrafts: [] -frontline_units: - - DIM' KAMIKAZE - - DIM' TOYOTA BLUE - - DIM' TOYOTA DESERT - - DIM' TOYOTA GREEN - - SPAAA LC with ZU-23 - - Scout LC with DSHK 12.7mm - - Scout LC with KORD 12.7mm - - Scout HL with DSHK 12.7mm - - Scout HL with KORD 12.7mm - - SPAAA HL with ZU-23 - - BRDM-2 - - Cobra - - MT-LB - - PT-76 - - ZU-23 on Ural-375 -artillery_units: - - 2S1 Gvozdika - - MLRS LC with B8M1 80mm - - MLRS HL with B8M1 80mm -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry RPG - - Insurgent AK-74 - - MANPADS SA-18 Igla "Grouse" - - Mortar 2B11 120mm -missiles: [] -air_defense_units: - - SA-9 Strela - - SPAAA LC with ZU-23 - - SPAAA HL with ZU-23 - - AAA ZU-23 Insurgent Closed Emplacement - - ZU-23 on Ural-375 Insurgent -preset_groups: [] -naval_units: [] diff --git a/resources/factions/insurgents_hard.yaml b/resources/factions/insurgents_hard.yaml deleted file mode 100644 index 19894a4ba..000000000 --- a/resources/factions/insurgents_hard.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -country: Insurgents -name: Insurgents (Hard) -authors: Khopa -description:

    Insurgents faction.

    -aircrafts: [] -frontline_units: - - DIM' KAMIKAZE - - DIM' TOYOTA BLUE - - DIM' TOYOTA DESERT - - DIM' TOYOTA GREEN - - SPAAA LC with ZU-23 - - Scout LC with DSHK 12.7mm - - Scout LC with KORD 12.7mm - - Scout HL with DSHK 12.7mm - - Scout HL with KORD 12.7mm - - SPAAA HL with ZU-23 - - BMP-1 - - BRDM-2 - - BTR-80 - - BTR-D - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - PT-76 - - T-55A - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 -artillery_units: - - 2S3 Akatsiya - - MLRS LC with B8M1 80mm - - MLRS HL with B8M1 80mm - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry RPG - - Insurgent AK-74 - - MANPADS SA-18 Igla "Grouse" - - Mortar 2B11 120mm -air_defense_units: - - SA-9 Strela - - ZSU-57-2 'Sparka' - - SPAAA LC with ZU-23 - - SPAAA HL with ZU-23 - - AAA ZU-23 Insurgent Closed Emplacement - - ZU-23 on Ural-375 Insurgent - - ZSU-23-4 Shilka -preset_groups: [] -naval_units: [] -missiles: - - SSM SS-1C Scud-B diff --git a/resources/factions/iran_1988.yaml b/resources/factions/iran_1988.yaml deleted file mode 100644 index c781a2afd..000000000 --- a/resources/factions/iran_1988.yaml +++ /dev/null @@ -1,63 +0,0 @@ ---- -country: Iran -name: Iran 1988 -authors: Malakhit -description:

    Iran at the end of the Iran-Iraq war

    -locales: - - fa_IR -aircrafts: - - AH-1J SeaCobra - - F-14A Tomcat (Block 135-GR Late) - - F-4E Phantom II - - F-5E Tiger II - - MiG-21bis Fishbed-N -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - Chieftain Mk.3 - - BMP-1 - - BTR-80 - - M113 - - M60A3 "Patton" - - ZSU-23-4 Shilka - - ZU-23 on Ural-375 - - ZSU-57-2 'Sparka' -artillery_units: - - 2S1 Gvozdika - - M109A6 Paladin - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry RPG - - Insurgent AK-74 - - MANPADS SA-18 Igla "Grouse" Ins -preset_groups: - - Hawk - - SA-2/S-75 - - HQ-2 - - Rapier - - Silkworm - - Cold-War-Flak -naval_units: - - Corvette 1241.1 Molniya - - FAC La Combattante IIa - - Frigate 1135M Rezky -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM Hawk SR (AN/MPQ-50) - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 - - AAA ZU-23 Insurgent Closed Emplacement - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -missiles: - - SSM SS-1C Scud-B -has_jtac: true -jtac_unit: MQ-9 Reaper -doctrine: coldwar diff --git a/resources/factions/iran_2015.yaml b/resources/factions/iran_2015.yaml deleted file mode 100644 index e35256cd5..000000000 --- a/resources/factions/iran_2015.yaml +++ /dev/null @@ -1,80 +0,0 @@ ---- -country: Iran -name: Iran 2015 -authors: Khopa -description:

    Iranian 2010s faction

    -locales: - - fa_IR -aircrafts: - - F-14A Tomcat (Block 135-GR Late) - - F-4E Phantom II - - F-5E Tiger II - - IL-76MD - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-28N Havoc - - MiG-21bis Fishbed-N - - MiG-29A Fulcrum-A - - Mirage-F1EQ - - Su-22M4 Fitter-K - - Su-24MK Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - Chieftain Mk.3 - - BMP-1 - - BMP-2 - - BTR-80 - - M113 - - M60A3 "Patton" - - T-72B with Kontakt-1 ERA - - ZSU-23-4 Shilka - - ZSU-57-2 'Sparka' -artillery_units: - - 2S1 Gvozdika - - M109A6 Paladin - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry RPG - - Insurgent AK-74 - - MANPADS SA-18 Igla "Grouse" Ins -preset_groups: - - Hawk - - SA-5/S-200 - - SA-2/S-75 - - HQ-2 - - SA-6 - - SA-11 - - Rapier - - SA-17 - - Silkworm -naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya - - FAC La Combattante IIa - - Frigate 1135M Rezky -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM Hawk SR (AN/MPQ-50) - - SA-15 Tor - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 - - AAA ZU-23 Insurgent Closed Emplacement - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -missiles: - - SSM SS-1C Scud-B -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - F-14A Tomcat (Block 135-GR Late): - - Rogue Nation(Top Gun - Maverick) diff --git a/resources/factions/iraq_1991.yaml b/resources/factions/iraq_1991.yaml deleted file mode 100644 index 0a14a51c5..000000000 --- a/resources/factions/iraq_1991.yaml +++ /dev/null @@ -1,73 +0,0 @@ ---- -country: Iraq -name: Iraq 1991 -authors: Hawkmoon -description:

    Iraq forces during desert Storm

    -aircrafts: - - IL-76MD - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - MiG-23ML Flogger-G - - MiG-25PD Foxbat-E - - MiG-29A Fulcrum-A - - Mirage-F1EQ - - SA 342M Gazelle - - Su-22M4 Fitter-K - - Su-24M Fencer-D - - Su-25 Frogfoot - - Tu-22M3 Backfire-C - - H-6J Badger -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - 2S1 Gvozdika - - Chieftain Mk.3 - - BMP-1 - - BRDM-2 - - BTR-80 - - MT-LB - - PT-76 - - T-55A - - T-72B with Kontakt-1 ERA - - ZSU-23-4 Shilka - - ZSU-57-2 'Sparka' -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - EWR 1L13 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -missiles: - - SSM SS-1C Scud-B -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -doctrine: coldwar diff --git a/resources/factions/israel_1948.yaml b/resources/factions/israel_1948.yaml deleted file mode 100644 index a3441c018..000000000 --- a/resources/factions/israel_1948.yaml +++ /dev/null @@ -1,38 +0,0 @@ ---- -country: Israel -name: Israel 1948 -authors: Khopa -description:

    Israel during the 1948 Arab-Israeli war.

    -locales: - - he_IL -aircrafts: - - B-17G Flying Fortress - - "Bf 109 K-4 Kurf\xFCrst" - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) -frontline_units: - - Bofors 40 mm Gun - - M2A1 Half-Track - - M4A2(75) Sherman - - M4A4 Sherman Firefly - - M8 Greyhound Light Armored Car -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Cold-War-Flak -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -cargo_ship: LST Mk.II diff --git a/resources/factions/israel_1973.yaml b/resources/factions/israel_1973.yaml deleted file mode 100644 index 0bf0e6e97..000000000 --- a/resources/factions/israel_1973.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -country: Israel -name: Israel 1973 -authors: Khopa -description:

    Israel during the 1973 Yom Kippur War.

    -locales: - - he_IL -aircrafts: - - A-4E Skyhawk - - F-4E Phantom II - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M2A1 Half-Track - - M48 Chaparral - - M4A2(75) Sherman - - M60A3 "Patton" -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -preset_groups: - - Hawk -naval_units: [] -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral - - Bofors 40 mm Gun -requirements: - Community A-4E: https://heclak.github.io/community-a4e-c/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: coldwar diff --git a/resources/factions/israel_1982.yaml b/resources/factions/israel_1982.yaml deleted file mode 100644 index ba80a01c4..000000000 --- a/resources/factions/israel_1982.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -country: Israel -name: Israel 1982 -authors: Khopa -description:

    Israel during the 1982 war with Lebanon.

    -locales: - - he_IL -aircrafts: - - A-4E Skyhawk - - AH-1W SuperCobra - - F-15C Eagle - - F-16A - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M163 Vulcan Air Defense System - - M60A3 "Patton" -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -preset_groups: - - Hawk -naval_units: [] -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: - Community A-4E: https://heclak.github.io/community-a4e-c/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/israel_2000.yaml b/resources/factions/israel_2000.yaml deleted file mode 100644 index f467d656d..000000000 --- a/resources/factions/israel_2000.yaml +++ /dev/null @@ -1,59 +0,0 @@ ---- -country: Israel -name: Israel 2000 -authors: Khopa -description:

    Modern Israeli faction.

    -locales: - - he_IL -aircrafts: - - AH-1W SuperCobra - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - C-130 - - C-130J-30 Super Hercules - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - UH-1H Iroquois - - UH-60L -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M113 - - M163 Vulcan Air Defense System - - Merkava Mk IV -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Patriot -naval_units: - - DDG Arleigh Burke IIa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - UH-60L: - - Israeli Air Force -unrestricted_satnav: true diff --git a/resources/factions/israel_2012.yaml b/resources/factions/israel_2012.yaml deleted file mode 100644 index 59a743d60..000000000 --- a/resources/factions/israel_2012.yaml +++ /dev/null @@ -1,79 +0,0 @@ ---- -country: Israel -name: Israel 2012'ish -authors: Headiii -description:

    A more modern Israeli faction with fictional Imports.

    -locales: - - he_IL -aircrafts: - - A-10C Thunderbolt II (Suite 3) - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - C-130 - - C-130J-30 Super Hercules - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F/A-18C Hornet (Lot 20) - - Mirage 2000C - - UH-1H Iroquois - - UH-60L -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M113 - - M163 Vulcan Air Defense System - - Merkava Mk IV -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Patriot -naval_units: - - DDG Arleigh Burke IIa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - A-10C Thunderbolt II (Suite 3): - - Fictional Israel 115 Sqn Flying Dragon - F-15C Eagle: - - 390th Fighter SQN - F-15E Strike Eagle: - - IDF No 69 Hammers Squadron - F-16CM Fighting Falcon (Block 50): - - IAF_101st_squadron - - IAF_110th_Squadron - - IAF_115th_Aggressors_Squadron - - IAF_117th_Squadron - UH-1H Iroquois: - - Israel Army - AH-64D Apache Longbow: - - ah-64_d_isr - F/A-18C Hornet (Lot 20): - - Fictional Israel Air Force - Mirage 2000C: - - UAE Air Force - UH-60L: - - Israeli Air Force -unrestricted_satnav: true diff --git a/resources/factions/italy_1990.yaml b/resources/factions/italy_1990.yaml deleted file mode 100644 index aa0360698..000000000 --- a/resources/factions/italy_1990.yaml +++ /dev/null @@ -1,50 +0,0 @@ ---- -country: Italy -name: Italy 1990 -authors: Khopa -description:

    Italy in the 90s.

    -locales: - - it_IT -aircrafts: - - AH-1W SuperCobra - - AV-8B Harrier II Night Attack - - C-130 - - F-104S Starfighter A/G - - F-104S Starfighter - - MB-339A - - Tornado IDS - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Leopard 1A3 - - M1097 Heavy HMMWV Avenger - - M113 -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk -naval_units: - - FFG Oliver Hazard Perry - - CG Ticonderoga - - LHA-1 Tarawa -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger -requirements: {} -carrier_names: [] -helicopter_carrier_names: - - Giuseppe Garibaldi - - Cavour -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/japan_1944.yaml b/resources/factions/japan_1944.yaml deleted file mode 100644 index 5ec9ab8d8..000000000 --- a/resources/factions/japan_1944.yaml +++ /dev/null @@ -1,41 +0,0 @@ ---- -country: Japan -name: Japan 1944 -authors: Ghosti -description:

    WW2 Japan faction that does not require the WW2 asset pack.

    -locales: - - ja_JP -aircrafts: - - I-16 Ishak - - Fw 190 A-8 Anton -frontline_units: - - 8.8 cm Flak 18 - - Panzerkampfwagen IV Ausf. H - - Sd.Kfz.251 "Hanomag" -artillery_units: - - Mortar 2B11 120mm -logistics_units: - - Truck Opel Blitz -infantry_units: - - Infantry AK-74 Rus -air_defense_units: - - 8.8 cm Flak 18 -preset_groups: [] -naval_units: [] -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -missiles: [] -has_jtac: false -doctrine: ww2 -building_set: ww2free -cargo_ship: LST Mk.II -liveries_overrides: - Fw 190 A-8 Anton: - - Fictional IJN 256th Kokutai Rai-153 - - Fictional IJN Carrier Akagi AI-103 - - Fictional IJN Carrier Akagi AI-151 - - Fictional IJN Carrier Soryu BI-112 - - Fictional IJN OTU Tsukuba Tsu-102 - I-16 Ishak: - - Japan diff --git a/resources/factions/japan_2005.yaml b/resources/factions/japan_2005.yaml deleted file mode 100644 index 2234449b2..000000000 --- a/resources/factions/japan_2005.yaml +++ /dev/null @@ -1,59 +0,0 @@ ---- -country: Japan -name: Japan 2005 -authors: Khopa -description: -

    Japanese self defense force, F-15C standing as F-15J, and F-16 as - Mitsubishi F-2.

    Ground units were also chosen to fit the existing vehicles - of the japanese forces

    -locales: - - ja_JP -aircrafts: - - AH-1W SuperCobra - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - C-130 - - C-130J-30 Super Hercules - - F-15J Eagle - - F-2A - - F-4EJ Kai Phantom II -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Flakpanzer Gepard - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1A2 Abrams - - Marder 1A3 - - Merkava Mk IV - - TPz Fuchs -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System - - MANPADS Stinger -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -preset_groups: - - Hawk - - Patriot -naval_units: - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - Flakpanzer Gepard -requirements: {} -carrier_names: [] -helicopter_carrier_names: - - Hyuga - - Ise -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/libya_2011.yaml b/resources/factions/libya_2011.yaml deleted file mode 100644 index 90c3e6fed..000000000 --- a/resources/factions/libya_2011.yaml +++ /dev/null @@ -1,62 +0,0 @@ ---- -country: Libya -name: Libya 2011 -authors: Khopa -description:

    Gaddafi's Lybian forces during the 2011 international intervention

    -aircrafts: - - IL-76MD - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - Su-17M4 Fitter-K - - Su-24M Fencer-D -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BRDM-2 - - PT-76 - - SAM SA-8 Osa "Gecko" TEL - - T-55A - - T-72B with Kontakt-1 ERA - - ZSU-23-4 Shilka -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Insurgent AK-74 - - MANPADS SA-18 Igla "Grouse" - - Paratrooper RPG-16 -preset_groups: - - SA-5/S-200 - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - Rapier - - HQ-7 -naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya - - FAC La Combattante IIa - - Frigate 1135M Rezky -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -missiles: - - SSM SS-1C Scud-B -requirements: {} -carrier_names: [] diff --git a/resources/factions/netherlands_1990.yaml b/resources/factions/netherlands_1990.yaml deleted file mode 100644 index 10707e5c0..000000000 --- a/resources/factions/netherlands_1990.yaml +++ /dev/null @@ -1,46 +0,0 @@ ---- -country: The Netherlands -name: Netherlands 1990 -authors: Khopa -description:

    Netherlands forces in the 90s.

    -locales: - - nl_NL -aircrafts: - - AH-64A Apache - - C-130 - - F-16CM Fighting Falcon (Block 50) - - F-5E Tiger II - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Leopard 1A3 - - M1097 Heavy HMMWV Avenger - - M113 -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk - - Rapier - - Patriot -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger - - Flakpanzer Gepard -requirements: {} -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/north_korea_2000.yaml b/resources/factions/north_korea_2000.yaml deleted file mode 100644 index da034f381..000000000 --- a/resources/factions/north_korea_2000.yaml +++ /dev/null @@ -1,65 +0,0 @@ ---- -country: North Korea -name: North Korea 2000 -authors: Khopa -description:

    North Korean army in the 2000s.

    -aircrafts: - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-15bis Fagot - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - MiG-29A Fulcrum-A -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BRDM-2 - - BTR-80 - - PT-76 - - SA-9 Strela - - T-55A - - T-72B with Kontakt-1 ERA - - T-80UD - - ZSU-57-2 'Sparka' -artillery_units: - - 2S19 Msta-S - - BM-21 Grad - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-5/S-200 - - SA-2/S-75 - - HQ-2 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 -naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -missiles: - - SSM SS-1C Scud-B -has_jtac: false diff --git a/resources/factions/nva_1970.yaml b/resources/factions/nva_1970.yaml deleted file mode 100644 index a492254fb..000000000 --- a/resources/factions/nva_1970.yaml +++ /dev/null @@ -1,46 +0,0 @@ ---- -country: Vietnam -name: NVA 1970 -authors: Starfire -description:

    North Vietnamese Army during the Vietnam War from 1965 to 1975

    -locales: - - vi_Vn -aircrafts: - - Mi-8MTV2 Hip - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N -awacs: [] -tankers: [] -frontline_units: - - T-55A - - PT-76 - - M2A1 Half-Track - - Grad MRL FDDM (FC) -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-3/S-125 - - KS-19 - - Cold-War-Flak -naval_units: - - Boat Armed Hi-speed - - Boat Schnellboot type S130 -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - S-60 57mm - - 8.8 cm Flak 18 - - ZSU-57-2 'Sparka' - - AAA ZU-23 Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka - -requirements: {} -doctrine: coldwar diff --git a/resources/factions/pakistan_2015.yaml b/resources/factions/pakistan_2015.yaml deleted file mode 100644 index 106efa3dc..000000000 --- a/resources/factions/pakistan_2015.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -country: Pakistan -name: Pakistan 2015 -authors: Khopa -description:

    Pakistan circa 2015 for JF-17 and F-16 enthusiasts.

    -aircrafts: - - AH-1W SuperCobra - - F-16CM Fighting Falcon (Block 50) - - JF-17 Thunder - - Mi-8MTV2 Hip - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - UH-1H Iroquois -awacs: - - KJ-2000 -tankers: - - IL-78M -frontline_units: - - BTR-80 - - HQ-7 Launcher - - M113 - - T-55A - - T-80UD - - Type 04A (ZBD-04A) -artillery_units: - - 2S9 Nona-S - - BM-30 Smerch (9M55K5 HE Rockets) -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS Stinger - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-2/S-75 - - HQ-2 - - SA-11 - - HQ-7 - - SA-10/S-300PS -naval_units: - - FFG Oliver Hazard Perry - - Type 054A Frigate -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 -carrier_names: [] -helicopter_carrier_names: [] -cruiser: [] -requirements: {} -has_jtac: true -jtac_unit: WingLoong-I diff --git a/resources/factions/peru_1995.yaml b/resources/factions/peru_1995.yaml deleted file mode 100644 index 3cd4b1e45..000000000 --- a/resources/factions/peru_1995.yaml +++ /dev/null @@ -1,50 +0,0 @@ ---- -country: Peru -name: Peru 1995 -authors: Dillie -description:

    Peru during the 1995 Cenepa War.

    -locales: - - es_ES -aircrafts: - - Mirage 2000C - - Mi-24V Hind-E - - Mi-8MTV2 Hip - - MB-339A - - Su-22M4 Fitter-K -frontline_units: - - T-55A - - M113 - - BRDM-2 - - BTR-80 - - M1043 HMMWV (M2 HMG) - - ZSU-23-4 Shilka -artillery_units: - - BM-21 Grad - - M109A6 Paladin -logistics_units: - - Truck Ural-4320T -infantry_units: - - Infantry AK-74 - - Infantry RPG - - Infantry M249 - - MANPADS SA-18 Igla "Grouse" -missiles: [] -preset_groups: - - SA-3/S-125 -naval_units: [] -air_defense_units: - - AAA ZU-23 Emplacement - - Bofors 40 mm Gun - - SAM P19 "Flat Face" SR (SA-2/3) - - ZSU-23-4 Shilka -carrier_names: [] -helicopter_carrier_names: [] -cruiser: [] -requirements: {} -has_jtac: false -doctrine: modern -liveries_overrides: - Mirage 2000C: - - Peru052 - MB-339A: - - MB339AP 'PERU' diff --git a/resources/factions/pmc_russian.yaml b/resources/factions/pmc_russian.yaml deleted file mode 100644 index 00604d856..000000000 --- a/resources/factions/pmc_russian.yaml +++ /dev/null @@ -1,34 +0,0 @@ ---- -country: Russia -name: Private Military Company - Russian -authors: Khopa -description:

    A private military company using Russian units.

    -locales: - - ru_RU -aircrafts: - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip -frontline_units: - - BRDM-2 - - BTR-80 - - Cobra - - SA-13 Gopher (9K35 Strela-10M3) -artillery_units: - - 2S19 Msta-S -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -air_defense_units: - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) -preset_groups: [] -naval_units: [] -missiles: [] diff --git a/resources/factions/pmc_russian_hard.yaml b/resources/factions/pmc_russian_hard.yaml deleted file mode 100644 index 8b85da742..000000000 --- a/resources/factions/pmc_russian_hard.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -country: Russia -name: Private Military Company - Russian (Hard) -authors: Starfire -description:

    A well-equipped private military company using a mix of modern and older Russian hardware.

    -locales: - - ru_RU -aircrafts: - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip -frontline_units: - - BMP-1 - - BRDM-2 - - BTR-80 - - BTR-D - - Cobra - - MT-LB - - PT-76 - - T-55A - - ZSU-57-2 'Sparka' -artillery_units: - - 2S1 Gvozdika - - 2S19 Msta-S - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -air_defense_units: - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - ZSU-23-4 Shilka -preset_groups: [] -naval_units: [] -missiles: [] diff --git a/resources/factions/pmc_us.yaml b/resources/factions/pmc_us.yaml deleted file mode 100644 index 9c29132cf..000000000 --- a/resources/factions/pmc_us.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -country: USA -name: Private Military Company - USA -authors: Khopa -description:

    A private military company using western units.

    -aircrafts: - - A-4E Skyhawk - - C-101CC Aviojet - - Mi-8MTV2 Hip - - SA 342M Gazelle - - UH-1H Iroquois -frontline_units: - - FV510 Warrior - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1097 Heavy HMMWV Avenger -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -air_defense_units: - - M1097 Heavy HMMWV Avenger -preset_groups: [] -naval_units: [] -missiles: [] -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/poland_2010.yaml b/resources/factions/poland_2010.yaml deleted file mode 100644 index 0189ceea8..000000000 --- a/resources/factions/poland_2010.yaml +++ /dev/null @@ -1,55 +0,0 @@ ---- -country: Poland -name: Poland 2010 -authors: Malakhit -description:

    Polish army in the 2010s.

    -locales: - - pl_PL -aircrafts: - - F-16CM Fighting Falcon (Block 50) - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-29A Fulcrum-A - - MiG-29G Fulcrum-A - - Su-22M4 Fitter-K -tankers: - - KC-130 -frontline_units: - - BMP-1 - - BRDM-2 - - Leopard 2A4 - - Leopard 2A5 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1126 Stryker ICV (M2 HMG) - - MT-LB - - T-72B3 model 2011 -artillery_units: - - 2S1 Gvozdika - - BM-21 Grad - - SpGH DANA -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS -missiles: [] -preset_groups: - - SA-5/S-200 - - SA-6 -naval_units: - - FFG Oliver Hazard Perry - - Corvette 1241.1 Molniya -air_defense_units: - - SAM SA-10 S-300 "Grumble" Big Bird SR - - SAM SA-8 Osa "Gecko" TEL - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -requirements: {} -carrier_names: [] -unrestricted_satnav: true diff --git a/resources/factions/redfor_china_2010.yaml b/resources/factions/redfor_china_2010.yaml deleted file mode 100644 index 3297661db..000000000 --- a/resources/factions/redfor_china_2010.yaml +++ /dev/null @@ -1,110 +0,0 @@ ---- -country: China -name: Redfor (China) 2010 -authors: Robert Peary -description: -

    Combined Redfor under China's leadership in the late 2000s, early - 2010s.

    -aircrafts: - - FC-1 Fierce Dragon - - IL-76MD - - J-11A Flanker-L - - J-15 Flanker X-2 - - J-7B - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-28N Havoc - - Mi-8MTV2 Hip - - MiG-29S Fulcrum-C - - MiG-31 Foxhound - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B - - Su-30MKK Flanker-G - - Su-34 Fullback - - Tu-22M3 Backfire-C - - H-6J Badger -awacs: - - KJ-2000 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BMP-3 - - BTR-80 - - BTR-82A - - HQ-7 Launcher - - SA-19 Grison (2K22 Tunguska) - - T-55A - - T-72B3 model 2011 - - T-80UD - - T-90A - - Type 04A (ZBD-04A) - - Type 96B (ZTZ-96B) -artillery_units: - - 2S19 Msta-S - - 2S9 Nona-S - - BM-27 Uragan - - BM-30 Smerch (9M55K5 HE Rockets) -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla "Grouse" - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-2/S-75 - - HQ-2 - - SA-6 - - SA-11 - - HQ-7 - - SA-10/S-300PS - - SA-10B/S-300PS - - SA-17 - - SA-12/S-300V - - SA-20/S-300PMU-1 - - SA-20B/S-300PMU-2 - - SA-23/S-300VM - - Chinese Navy -naval_units: - - Frigate 1135M Rezky - - Type 052B Destroyer - - Type 052C Destroyer - - Corvette 1241.1 Molniya - - Type 054A Frigate - - CV 1143.5 Admiral Kuznetsov - - Type 071 Amphibious Transport Dock -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -carrier_names: - - 001 Liaoning - - 002 Shandong -helicopter_carrier_names: - - Kunlun Shan - - Jinggang Shan - - Changbai Shan - - Yimeng Shan - - Longhu Shan - - Wuzhi Shan - - Wudang Shan -requirements: {} -has_jtac: true -jtac_unit: WingLoong-I diff --git a/resources/factions/redfor_russia_2010.yaml b/resources/factions/redfor_russia_2010.yaml deleted file mode 100644 index 62b6b44e6..000000000 --- a/resources/factions/redfor_russia_2010.yaml +++ /dev/null @@ -1,106 +0,0 @@ ---- -country: Russia -name: Redfor (Russia) 2010 -authors: Robert Peary -description: -

    Combined Redfor under Russia's leadership in the late 2000s, early - 2010s.

    -locales: - - ru_RU -aircrafts: - - IL-76MD - - J-11A Flanker-L - - JF-17 Thunder - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-28N Havoc - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-29S Fulcrum-C - - MiG-31 Foxhound - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B - - Su-30 Flanker-C - - Su-33 Flanker-D - - Su-34 Fullback - - Tu-22M3 Backfire-C -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BMP-3 - - BTR-80 - - BTR-82A - - HQ-7 Launcher - - SA-19 Grison (2K22 Tunguska) - - T-55A - - T-72B3 model 2011 - - T-80UD - - T-90A - - Type 04A (ZBD-04A) - - Type 96B (ZTZ-96B) -artillery_units: - - 2S19 Msta-S - - 2S9 Nona-S - - BM-27 Uragan - - BM-30 Smerch (9M55K5 HE Rockets) -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla "Grouse" - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-6 - - SA-11 - - HQ-7 - - SA-10/S-300PS - - SA-10B/S-300PS - - SA-17 - - SA-12/S-300V - - SA-20/S-300PMU-1 - - SA-20B/S-300PMU-2 - - SA-23/S-300VM - - Russian Navy -naval_units: - - SSK 877V Kilo - - Frigate 1135M Rezky - - Type 052B Destroyer - - Type 052C Destroyer - - Corvette 1241.1 Molniya - - Type 054A Frigate - - CV 1143.5 Admiral Kuznetsov - - Type 071 Amphibious Transport Dock -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: - - Ivan Rogov - - Mitrofan Moskalenko -requirements: {} -carrier_names: - - Admiral Kuznetsov -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/russia_1955.yaml b/resources/factions/russia_1955.yaml deleted file mode 100644 index e032f7668..000000000 --- a/resources/factions/russia_1955.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -country: Russia -name: Russia 1955 -authors: Khopa -description:

    Soviet army around 1955, during the Korean War

    -locales: - - ru_RU -aircrafts: - - MiG-15bis Fagot - - Mi-8MTV2 Hip -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - 8.8 cm Flak 18 - - BRDM-2 - - Grad MRL FDDM (FC) - - MT-LB - - PT-76 - - S-60 57mm - - T-55A - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG -missiles: [] -air_defense_units: [] -preset_groups: - - KS-19 - - Cold-War-Flak -naval_units: [] -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -has_jtac: false -doctrine: coldwar diff --git a/resources/factions/russia_1965.yaml b/resources/factions/russia_1965.yaml deleted file mode 100644 index 533f6c5ba..000000000 --- a/resources/factions/russia_1965.yaml +++ /dev/null @@ -1,53 +0,0 @@ ---- -country: Russia -name: Russia 1965 -authors: Khopa -description:

    Soviet army in the 60s, ideal to fly the Mig-19 or the Mig-21.

    -locales: - - ru_RU -aircrafts: - - Mi-8MTV2 Hip - - MiG-15bis Fagot - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - Tu-95MS Bear-H -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMD-1 - - BMP-1 - - BRDM-2 - - BTR-80 - - BTR-D - - PT-76 - - S-60 57mm - - T-55A - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-3/S-125 - - Cold-War-Flak -naval_units: [] -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -has_jtac: false -doctrine: coldwar diff --git a/resources/factions/russia_1975.yaml b/resources/factions/russia_1975.yaml deleted file mode 100644 index e7effc4f6..000000000 --- a/resources/factions/russia_1975.yaml +++ /dev/null @@ -1,71 +0,0 @@ ---- -country: Russia -name: Russia 1975 -authors: Khopa -description:

    Soviet army in the late 70s, using their prototype Mig-29A and Mi-24P.

    -locales: - - ru_RU -aircrafts: - - IL-76MD - - Mi-24P Hind-F - - Mi-24V Hind-E - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - MiG-25PD Foxbat-E - - MiG-29A Fulcrum-A - - Su-17M4 Fitter-K - - Su-24M Fencer-D - - Su-25 Frogfoot - - Tu-142 Bear-F - - Tu-95MS Bear-H -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMD-1 - - BMP-1 - - BRDM-2 - - BTR-80 - - PT-76 - - SAM SA-8 Osa "Gecko" TEL - - T-55A -artillery_units: - - 2S1 Gvozdika - - 2S9 Nona-S - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - Mortar 2B11 120mm -preset_groups: - - SA-5/S-200 - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - Cold-War-Flak -naval_units: - - Corvette 1241.1 Molniya -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -missiles: - - SSM SS-1C Scud-B -requirements: {} -carrier_names: [] -has_jtac: false -doctrine: coldwar diff --git a/resources/factions/russia_1990.yaml b/resources/factions/russia_1990.yaml deleted file mode 100644 index 86e488479..000000000 --- a/resources/factions/russia_1990.yaml +++ /dev/null @@ -1,82 +0,0 @@ ---- -country: Russia -name: Russia 1990 -authors: Khopa -description:

    Soviet/Russian army in the 90s.

    -locales: - - ru_RU -aircrafts: - - IL-76MD - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-25PD Foxbat-E - - MiG-29S Fulcrum-C - - MiG-31 Foxhound - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B - - Su-33 Flanker-D - - Tu-142 Bear-F - - Tu-160 Blackjack - - Tu-22M3 Backfire-C - - Tu-95MS Bear-H -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BTR-80 - - SA-13 Gopher (9K35 Strela-10M3) - - T-72B with Kontakt-1 ERA - - T-80UD -artillery_units: - - 2S19 Msta-S - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - SA-11 - - SA-10/S-300PS - - Russian Navy -naval_units: - - Frigate 1135M Rezky - - Corvette 1241.1 Molniya - - CV 1143.5 Admiral Kuznetsov -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: - - Admiral Kuznetsov - - Admiral Gorshkov -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/russia_2010.yaml b/resources/factions/russia_2010.yaml deleted file mode 100644 index 754831ed9..000000000 --- a/resources/factions/russia_2010.yaml +++ /dev/null @@ -1,89 +0,0 @@ ---- -country: Russia -name: Russia 2010 -authors: Khopa -description:

    Russian army in the early 2010s.

    -locales: - - ru_RU -aircrafts: - - IL-76MD - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-28N Havoc - - Mi-8MTV2 Hip - - MiG-29S Fulcrum-C - - MiG-31 Foxhound - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B - - Su-30 Flanker-C - - Su-33 Flanker-D - - Su-34 Fullback - - Tu-142 Bear-F - - Tu-160 Blackjack - - Tu-22M3 Backfire-C - - Tu-95MS Bear-H -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BMP-3 - - BTR-80 - - BTR-82A - - SA-19 Grison (2K22 Tunguska) - - T-72B3 model 2011 - - T-80UD - - T-90A -artillery_units: - - 2S19 Msta-S - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla "Grouse" - - Mortar 2B11 120mm - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-11 - - SA-10/S-300PS - - SA-10B/S-300PS - - SA-17 - - SA-12/S-300V - - SA-20/S-300PMU-1 - - SA-20B/S-300PMU-2 - - SA-23/S-300VM - - Russian Navy -naval_units: - - Frigate 1135M Rezky - - Corvette 1241.1 Molniya - - CV 1143.5 Admiral Kuznetsov - - LS Ropucha - - SSK 636 Improved Kilo -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: - - Admiral Kuznetsov -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/russia_2020.yaml b/resources/factions/russia_2020.yaml deleted file mode 100644 index 32e34b15d..000000000 --- a/resources/factions/russia_2020.yaml +++ /dev/null @@ -1,85 +0,0 @@ ---- -country: Russia -name: Russia 2020 -authors: Khopa -description:

    Russia in 2020, using the Su-57 mod by Cubanace.

    -locales: - - ru_RU -aircrafts: - - IL-76MD - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-28N Havoc - - Mi-8MTV2 Hip - - MiG-29S Fulcrum-C - - MiG-31 Foxhound - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B - - Su-30 Flanker-C - - Su-33 Flanker-D - - Su-34 Fullback - - Su-57 Felon - - Tu-142 Bear-F - - Tu-160 Blackjack - - Tu-22M3 Backfire-C - - Tu-95MS Bear-H -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-2 - - BMP-3 - - SA-19 Grison (2K22 Tunguska) - - T-72B with Kontakt-1 ERA - - T-80UD - - T-90A -artillery_units: - - 2S19 Msta-S - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-11 - - SA-10/S-300PS - - SA-10B/S-300PS - - SA-17 - - SA-12/S-300V - - SA-20/S-300PMU-1 - - SA-20B/S-300PMU-2 - - SA-23/S-300VM - - Russian Navy -naval_units: - - Frigate 1135M Rezky - - Corvette 1241.1 Molniya - - CV 1143.5 Admiral Kuznetsov -air_defense_units: - - EWR 1L13 - - EWR 55G6 - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: - SU-57 Felon By CubanAce Simulations: https://www.digitalcombatsimulator.com/fr/files/2539621/ -carrier_names: - - Admiral Kuznetsov -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/soviet_union_1943.yaml b/resources/factions/soviet_union_1943.yaml deleted file mode 100644 index c94fecea0..000000000 --- a/resources/factions/soviet_union_1943.yaml +++ /dev/null @@ -1,40 +0,0 @@ ---- -country: USSR -name: Soviet Union 1943 -authors: Khopa -description: -

    Soviet Union in 1943. Featuring the I16, and using some allies units to - represent either lend leased vehicles or soviet equivalent vehicles. BM-21 is - used to represent BM-13

    -locales: - - ru_RU -aircrafts: - - I-16 Ishak - - Spitfire LF Mk IX -frontline_units: - - A17 Light Tank Mk VII Tetrarch - - Bofors 40 mm Gun - - Daimler Armoured Car Mk I - - M2A1 Half-Track - - M4A2(75) Sherman -artillery_units: - - BM-21 Grad -logistics_units: - - Truck Bedford - - Truck GMC "Jimmy" 6x6 Truck -infantry_units: - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Ally Flak -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II diff --git a/resources/factions/spain_1990.yaml b/resources/factions/spain_1990.yaml deleted file mode 100644 index ed7615631..000000000 --- a/resources/factions/spain_1990.yaml +++ /dev/null @@ -1,70 +0,0 @@ ---- -country: Spain -name: Spain 1990 -authors: Khopa -description:

    Spain in the 90s

    -locales: - - es_ES -aircrafts: - - AV-8B Harrier II Night Attack - - C-130 - - C-101CC Aviojet - - EF-18A+ Hornet - - F-5E Tiger II - - Mirage-F1BE - - Mirage-F1CE - - Mirage-F1EE - - Mirage-F1M-CE - - Mirage-F1M-EE - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Leopard 2A4 - - M1097 Heavy HMMWV Avenger - - M113 - - M60A3 "Patton" -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -preset_groups: - - Hawk - - Roland - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger -requirements: {} -carrier_names: - - Principe de Asturias -helicopter_carrier_names: - - Juan Carlos I -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - EF-18A+ Hornet: - - Spain 111th Escuadron C.15-73 - - Spain 111th Escuadron C.15-88 - - Spain 121th Escuadron C.15-45 - - Spain 121th Escuadron C.15-50 - - Spain 121th Escuadron C.15-60 - - Spain 151th Escuadron C.15-14 - - Spain 151th Escuadron C.15-18 - - Spain 151th Escuadron C.15-23 - - Spain 151th Escuadron C.15-24 - - Spain 211th Escuadron C.15-76 - - Spain 211th Escuadron C.15-77 - - Spain 462th Escuadron C.15-79 - - Spain 462th Escuadron C.15-90 diff --git a/resources/factions/sweden_1970.yaml b/resources/factions/sweden_1970.yaml deleted file mode 100644 index 4d24549e4..000000000 --- a/resources/factions/sweden_1970.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -country: Sweden -name: Sweden 1970s Alternate Universe -authors: Starfire -description: -

    Sweden 1970

    Since we do not yet have Heatblur's AI Draken, this - faction includes the Mirage F1CE in order to provide Sweden with some form of A2A - capability.

    -locales: - - sv_SE -aircrafts: - - AJS-37 Viggen - - Mirage-F1CE - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - Leopard 2A4 - - M1126 Stryker ICV (M2 HMG) - - M48 Chaparral -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -missiles: [] -preset_groups: - - Hawk - - Cold-War-Flak -naval_units: - - FFG Oliver Hazard Perry -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -has_jtac: false -doctrine: coldwar diff --git a/resources/factions/sweden_1990.yaml b/resources/factions/sweden_1990.yaml deleted file mode 100644 index 688806774..000000000 --- a/resources/factions/sweden_1990.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -country: Sweden -name: Sweden 1990 -authors: Khopa -description: - "

    Sweden in the 90s.

    Note : Since we're missing the Draken and - the Air-to-Air variant of the Viggen, this faction will struggle in air-to-air scenarios.

    " -locales: - - sv_SE -aircrafts: - - AJS-37 Viggen - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - Leopard 2A4 - - M1097 Heavy HMMWV Avenger - - M1126 Stryker ICV (M2 HMG) -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/sweden_2002.yaml b/resources/factions/sweden_2002.yaml deleted file mode 100644 index 893e9ce38..000000000 --- a/resources/factions/sweden_2002.yaml +++ /dev/null @@ -1,41 +0,0 @@ ---- -country: Sweden -name: Sweden 2002 -authors: Khopa (updated with Gripen by bgreman) -description:

    Sweden in 2002 after the addition of the Gripen-C.

    -locales: - - sv_SE -aircrafts: - - AJS-37 Viggen - - JAS 39 Gripen - - JAS 39 Gripen A/G - - UH-1H Iroquois -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - FV510 Warrior - - Leopard 2A4 - - M1097 Heavy HMMWV Avenger - - M1126 Stryker ICV (M2 HMG) -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger -preset_groups: - - Hawk -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger -requirements: - JAS39 Gripen Mod by Community: https://github.com/whisky-actual/Community-JAS-39-C -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/syria_1948.yaml b/resources/factions/syria_1948.yaml deleted file mode 100644 index a3a6e3216..000000000 --- a/resources/factions/syria_1948.yaml +++ /dev/null @@ -1,32 +0,0 @@ ---- -country: Syria -name: Syria 1948 -authors: Khopa -description:

    Syria and Arab armies in the 1948 war against Israel.

    -aircrafts: - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) -frontline_units: - - Bofors 40 mm Gun - - M4A2(75) Sherman - - Panzerkampfwagen IV Ausf. H - - Sd.Kfz.234/2 Puma - - Sd.Kfz.251 "Hanomag" -artillery_units: [] -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: [] -preset_groups: - - Flak -naval_units: - - Boat Schnellboot type S130 -helicopter_carrier_names: [] -carrier_names: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -doctrine: ww2 -cargo_ship: LST Mk.II diff --git a/resources/factions/syria_1967.yaml b/resources/factions/syria_1967.yaml deleted file mode 100644 index 3e7fac3c0..000000000 --- a/resources/factions/syria_1967.yaml +++ /dev/null @@ -1,48 +0,0 @@ ---- -country: Syria -name: Syria 1967 -authors: Khopa -description:

    Syria and Arab armies in the 1967 6 days war against Israel.

    -aircrafts: - - Mi-8MTV2 Hip - - MiG-15bis Fagot - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - Su-17M4 Fitter-K -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BRDM-2 - - PT-76 - - Panzerkampfwagen IV Ausf. H - - S-60 57mm - - T-55A - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - Paratrooper AKS -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-3/S-125 -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -doctrine: coldwar diff --git a/resources/factions/syria_1967_with_ww2_weapons.yaml b/resources/factions/syria_1967_with_ww2_weapons.yaml deleted file mode 100644 index 9f8cb70a4..000000000 --- a/resources/factions/syria_1967_with_ww2_weapons.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -country: Syria -name: Syria 1967 (With WW2 Weapons) -authors: Khopa -description: -

    Syria and Arab armies in the 1967 6 days war against Israel. Using - WW2 units to be more accurate (Yes, Syria used Panzer IV, Stug III and Jagdpanzer - IV during this war)

    -aircrafts: - - Mi-8MTV2 Hip - - MiG-15bis Fagot - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - Su-17M4 Fitter-K -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BRDM-2 - - Jagdpanzer IV - - PT-76 - - Panzerkampfwagen IV Ausf. H - - S-60 57mm - - "Sturmgesch\xFCtz III Ausf. G" - - T-55A - - ZSU-57-2 'Sparka' -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - Paratrooper AKS -missiles: [] -preset_groups: - - SA-2/S-75 - - SA-3/S-125 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -helicopter_carrier_names: [] -carrier_names: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -doctrine: coldwar diff --git a/resources/factions/syria_1973.yaml b/resources/factions/syria_1973.yaml deleted file mode 100644 index f7f44a787..000000000 --- a/resources/factions/syria_1973.yaml +++ /dev/null @@ -1,53 +0,0 @@ ---- -country: Syria -name: Syria 1973 -authors: Khopa -description:

    Syria and Arab armies during the Yom Kippur War

    -aircrafts: - - Mi-8MTV2 Hip - - MiG-15bis Fagot - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - Su-17M4 Fitter-K -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - MT-LB - - PT-76 - - S-60 57mm - - T-55A - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Infantry RPG - - Paratrooper AKS -preset_groups: - - SA-2/S-75 - - SA-3/S-125 - - SA-6 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -missiles: - - SSM SS-1C Scud-B -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] -doctrine: coldwar diff --git a/resources/factions/syria_1982.yaml b/resources/factions/syria_1982.yaml deleted file mode 100644 index 81014a4c3..000000000 --- a/resources/factions/syria_1982.yaml +++ /dev/null @@ -1,59 +0,0 @@ ---- -country: Syria -name: Syria 1982 -authors: Khopa -description:

    Syria and Arab armies in the 1982 invasion of Lebanon

    -aircrafts: - - Mi-8MTV2 Hip - - MiG-19P Farmer-B - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - MiG-25PD Foxbat-E - - Su-17M4 Fitter-K -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - MT-LB - - PT-76 - - S-60 57mm - - T-55A - - T-72B with Kontakt-1 ERA - - ZSU-57-2 'Sparka' - - ZU-23 on Ural-375 -artillery_units: - - BM-21 Grad -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - EWR 1L13 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - ZSU-57-2 'Sparka' - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -missiles: - - SSM SS-1C Scud-B -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] diff --git a/resources/factions/syria_2011.yaml b/resources/factions/syria_2011.yaml deleted file mode 100644 index f5fe633c6..000000000 --- a/resources/factions/syria_2011.yaml +++ /dev/null @@ -1,78 +0,0 @@ ---- -country: Combined Joint Task Forces Red -name: Syria 2011 -authors: Khopa -description:

    Syrian Arab Army at the start of the Syrian Civil War.

    -aircrafts: - - IL-76MD - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-21bis Fishbed-N - - MiG-23MLD Flogger-K - - MiG-25PD Foxbat-E - - MiG-29S Fulcrum-C - - SA 342L Gazelle - - SA 342M Gazelle - - Su-17M4 Fitter-K - - Su-24M Fencer-D -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BRDM-2 - - BTR-80 - - Cobra - - MT-LB - - PT-76 - - T-55A - - T-72B with Kontakt-1 ERA - - T-90A - - ZSU-57-2 'Sparka' -artillery_units: - - 2S1 Gvozdika - - 2S9 Nona-S - - BM-21 Grad - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-5/S-200 - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - SA-11 - - SA-17 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -missiles: - - SSM SS-1C Scud-B -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] diff --git a/resources/factions/syria_2012.yaml b/resources/factions/syria_2012.yaml deleted file mode 100644 index 94a97d54d..000000000 --- a/resources/factions/syria_2012.yaml +++ /dev/null @@ -1,82 +0,0 @@ ---- -country: Combined Joint Task Forces Red -name: Syria 2012'ish -authors: Headiii -description: -

    Syrian Army with more modern Imports and supported by a Russian Expeditionary - Force.

    -aircrafts: - - IL-76MD - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-23MLD Flogger-K - - MiG-25PD Foxbat-E - - MiG-29S Fulcrum-C - - SA 342L Gazelle - - SA 342M Gazelle - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-30 Flanker-C - - Su-34 Fullback -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-1 - - BMP-2 - - BRDM-2 - - BTR-80 - - Cobra - - MT-LB - - PT-76 - - T-55A - - T-72B with Kontakt-1 ERA - - T-90A - - ZSU-57-2 'Sparka' -artillery_units: - - 2S1 Gvozdika - - 2S9 Nona-S - - BM-21 Grad - - BM-27 Uragan -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -preset_groups: - - SA-5/S-200 - - SA-2/S-75 - - SA-2/S-75 V-759/5V23 - - SA-3/S-125 - - SA-3/S-125 V-601P/5V27 - - SA-6 - - SA-11 - - SA-10/S-300PS - - SA-17 - - Cold-War-Flak -naval_units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya -air_defense_units: - - SAM P19 "Flat Face" SR (SA-2/3) - - EWR 1L13 - - EWR 55G6 - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -missiles: - - SSM SS-1C Scud-B -helicopter_carrier_names: [] -requirements: {} -carrier_names: [] diff --git a/resources/factions/turkey_2005.yaml b/resources/factions/turkey_2005.yaml deleted file mode 100644 index 9a70c134e..000000000 --- a/resources/factions/turkey_2005.yaml +++ /dev/null @@ -1,54 +0,0 @@ ---- -country: Turkey -name: Turkey 2005 -authors: Khopa -description:

    Turkish army in the mid/late 2000s.

    -locales: - - tr_TR -aircrafts: - - AH-1W SuperCobra - - C-130 - - CH-47D - - F-16CM Fighting Falcon (Block 50) - - F-4E Phantom II - - OH-58D Kiowa Warrior - - UH-1H Iroquois - - UH-60A - - UH-60L -awacs: - - E-3A -tankers: - - KC-135 Stratotanker -frontline_units: - - BTR-80 - - Cobra - - Leopard 1A3 - - Leopard 2A4 Trs - - M1097 Heavy HMMWV Avenger - - M113 - - M60A3 "Patton" -artillery_units: - - Firtina - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS -missiles: [] -preset_groups: - - Hawk - - SA-3/S-125 - - Rapier -naval_units: - - FFG Oliver Hazard Perry -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger - - ZSU-23-4 Shilka -has_jtac: true -jtac_unit: MQ-9 Reaper -unrestricted_satnav: true diff --git a/resources/factions/uae_2005.yaml b/resources/factions/uae_2005.yaml deleted file mode 100644 index 8f472300d..000000000 --- a/resources/factions/uae_2005.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -country: United Arab Emirates -name: United Arab Emirates 2005 -authors: Khopa -description:

    UAR army in the 2000s.

    -aircrafts: - - AH-64D Apache Longbow (AI) - - AH-64D Apache Longbow - - C-130 - - F-16CM Fighting Falcon (Block 50) - - MB-339A - - Mirage 2000-5 - - Mirage 2000C -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - BMP-3 - - "Leclerc S\xE9ries 2" - - TPz Fuchs -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS SA-18 Igla-S "Grouse" -preset_groups: - - Hawk - - Rapier -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) -requirements: {} -carrier_names: [] -has_jtac: true -jtac_unit: WingLoong-I -unrestricted_satnav: true diff --git a/resources/factions/uae_2015.yaml b/resources/factions/uae_2015.yaml deleted file mode 100644 index 2e6195bea..000000000 --- a/resources/factions/uae_2015.yaml +++ /dev/null @@ -1,47 +0,0 @@ ---- -country: United Arab Emirates -name: United Arab Emirates 2015 -authors: Khopa -description:

    UAE army in the 2010s.

    -aircrafts: - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - C-130 - - C-130J-30 Super Hercules - - C-17A - - CH-47D - - F-16CM Fighting Falcon (Block 50) - - Mirage 2000-5 - - Mirage 2000C - - UH-60A - - UH-60L -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - BMP-3 - - "Leclerc S\xE9ries 2" - - TPz Fuchs -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS SA-18 Igla-S "Grouse" -preset_groups: - - Hawk - - Rapier - - Patriot -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar -requirements: {} -carrier_names: [] -has_jtac: true -jtac_unit: WingLoong-I -unrestricted_satnav: true diff --git a/resources/factions/uk_1944.yaml b/resources/factions/uk_1944.yaml deleted file mode 100644 index 4843a3090..000000000 --- a/resources/factions/uk_1944.yaml +++ /dev/null @@ -1,49 +0,0 @@ ---- -country: UK -name: United Kingdom 1944 -authors: Khopa -description:

    United Kingdom army in 1944.

    -locales: - - en_UK -aircrafts: - - Boston Mk.III - - Fortress Mk.III - - Mustang Mk.IV (Early) - - Mustang Mk.IV (Late) - - Spitfire LF Mk IX - - Spitfire LF Mk IX (Clipped Wings) - - Thunderbolt Mk.II (Early) - - Thunderbolt Mk.II (Late) - - Thunderbolt Mk.II (Mid) - - MosquitoFBMkVI -frontline_units: - - A17 Light Tank Mk VII Tetrarch - - A22 Infantry Tank MK IV Churchill VII - - A27L Cruiser Tank MK VIII Centaur IV - - A27M Cruiser Tank MK VIII Cromwell IV - - Daimler Armoured Car Mk I - - M2A1 Half-Track - - QF 40 mm Mark III - - Sherman Firefly VC - - Sherman III -artillery_units: [] -logistics_units: - - Truck Bedford - - Truck GMC "Jimmy" 6x6 Truck -infantry_units: - - Infantry SMLE No.4 Mk-1 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Ally Flak - - WW2LST -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II diff --git a/resources/factions/uk_1990.yaml b/resources/factions/uk_1990.yaml deleted file mode 100644 index 60443b6f1..000000000 --- a/resources/factions/uk_1990.yaml +++ /dev/null @@ -1,62 +0,0 @@ ---- -country: UK -name: United Kingdom 1990 -authors: Khopa -description:

    United Kingdom Army in the 1990s.

    -locales: - - en_UK -aircrafts: - - AH-64A Apache - - AV-8B Harrier II Night Attack - - C-130 - - C-130J-30 Super Hercules - - Gazelle AH.1 - - Phantom F.3 - - Tornado GR4 -awacs: - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - Chieftain Mk.3 - - FV4034 Challenger 2 - - FV510 Warrior - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Hawk - - Rapier -naval_units: - - CG Ticonderoga - - CVN-74 John C. Stennis - - Castle Class - - DDG Arleigh Burke IIa - - FFG Oliver Hazard Perry - - HMS Achilles (F12) - - HMS Andromeda (F57) - - HMS Ariadne (F72) - - HMS Invincible (R05) -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M1097 Heavy HMMWV Avenger -requirements: {} -carrier_names: [] -helicopter_carrier_names: - - HMS Invincible - - HMS Illustrious - - HMS Ark Royal -has_jtac: true -jtac_unit: MQ-9 Reaper diff --git a/resources/factions/ukraine_2010.yaml b/resources/factions/ukraine_2010.yaml deleted file mode 100644 index d5baddc09..000000000 --- a/resources/factions/ukraine_2010.yaml +++ /dev/null @@ -1,62 +0,0 @@ ---- -country: Ukraine -name: Ukraine 2010 -authors: Khopa -description:

    Ukrainian army in the 2010s.

    -aircrafts: - - IL-76MD - - L-39ZA Albatros - - Mi-24V Hind-E - - Mi-24P Hind-F - - Mi-8MTV2 Hip - - MiG-29S Fulcrum-C - - Su-24M Fencer-D - - Su-25 Frogfoot - - Su-25T Frogfoot - - Su-27 Flanker-B -awacs: - - A-50 -tankers: - - IL-78M -frontline_units: - - BMP-2 - - BMP-3 - - BTR-80 - - M1043 HMMWV (M2 HMG) - - SA-13 Gopher (9K35 Strela-10M3) - - T-72B with Kontakt-1 ERA - - T-80UD -artillery_units: [] -logistics_units: - - LUV UAZ-469 Jeep - - Truck Ural-375 -infantry_units: - - Infantry AK-74 Rus - - MANPADS SA-18 Igla-S "Grouse" - - Paratrooper AKS - - Paratrooper RPG-16 -missiles: [] -preset_groups: - - SA-5/S-200 - - SA-3/S-125 - - SA-6 - - SA-11 - - SA-10/S-300PS - - SA-17 - - SA-20/S-300PMU-1 -naval_units: - - Corvette 1124.4 Grish -air_defense_units: - - SAM SA-10 S-300 "Grumble" Big Bird SR - - SAM SA-8 Osa "Gecko" TEL - - SA-9 Strela - - SA-13 Gopher (9K35 Strela-10M3) - - SA-15 Tor - - SA-19 Grison (2K22 Tunguska) - - AAA ZU-23 Closed Emplacement - - ZU-23 on Ural-375 - - ZSU-23-4 Shilka -requirements: {} -carrier_names: - - Admiral Kuznetsov - - Admiral Gorshkov diff --git a/resources/factions/unc_1950_fictional.yaml b/resources/factions/unc_1950_fictional.yaml deleted file mode 100644 index 5283b20eb..000000000 --- a/resources/factions/unc_1950_fictional.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -country: USA -name: United Nations Command 1950, fictional -authors: BenBenBeartrax -description: -

    Fictional United Nations Command around 1955 during the Korean War, with - some WW2 planes added in place of their post-war counterparts.

    -aircrafts: - - A-20G Havoc - - B-17G Flying Fortress - - F-86F Sabre - - P-47D-40 Thunderbolt - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang -frontline_units: - - Bofors 40 mm Gun - - M2A1 Half-Track - - M4A2(75) Sherman - - M60A3 "Patton" - - M8 Greyhound Light Armored Car -artillery_units: - - M12 Gun Motor Carriage -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Cold-War-Flak - - Ally Flak -naval_units: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ diff --git a/resources/factions/us_aggressors.yaml b/resources/factions/us_aggressors.yaml deleted file mode 100644 index 55a781a97..000000000 --- a/resources/factions/us_aggressors.yaml +++ /dev/null @@ -1,83 +0,0 @@ ---- -country: USAF Aggressors -name: USAF Aggressors -authors: Khopa -description:

    USAF aggresors.

    -locales: - - en_US -aircrafts: - - A-10A Thunderbolt II - - A-10C Thunderbolt II (Suite 3) - - A-4E Skyhawk - - AH-64D Apache Longbow (AI) - - AH-64D Apache Longbow - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - F-117A Nighthawk - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F/A-18C Hornet (Lot 20) - - Ka-50 Hokum - - Ka-50 Hokum (Blackshark 3) - - MB-339A - - Mi-24P Hind-F - - SH-60B Seahawk - - Su-27 Flanker-B - - UH-1H Iroquois -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-135 Stratotanker - - KC-135 Stratotanker MPRS - - S-3B Tanker -frontline_units: - - LAV-25 - - Leopard 2A4 - - M1043 HMMWV (M2 HMG) - - M1097 Heavy HMMWV Avenger - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -preset_groups: - - Hawk - - Patriot -naval_units: - - FFG Oliver Hazard Perry -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger -requirements: {} -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - F/A-18C Hornet (Lot 20): - - NAWDC black - - NSAWC brown splinter - - VFC-12 - F-15C Eagle: - - 65th Aggressor SQN (WA) MiG - - 65th Aggressor SQN (WA) MiG - - 65th Aggressor SQN (WA) SUPER_Flanker - F-16CM Fighting Falcon (Block 50): - - 64th_aggressor_squadron_ghost - - usaf 64th aggressor sqn - shark - - usaf 64th aggressor sqn-splinter - F-14B Tomcat: - - vf-74 adversary diff --git a/resources/factions/usa_1944.yaml b/resources/factions/usa_1944.yaml deleted file mode 100644 index f91a090e1..000000000 --- a/resources/factions/usa_1944.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -country: USA -name: USA 1944 -authors: Khopa -description:

    US army in 1944, western front.

    -locales: - - en_US -aircrafts: - - A-20G Havoc - - B-17G Flying Fortress - - C-47 Skytrain - - P-47D-30 Thunderbolt (Early) - - P-47D-30 Thunderbolt (Late) - - P-47D-40 Thunderbolt - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - Spitfire LF Mk IX -frontline_units: - - M10 3-inch Gun Motor Carriage - - M2A1 Half-Track - - M4A2(75) Sherman - - M4A4 Sherman Firefly - - M8 Greyhound Light Armored Car - - QF 3.7-inch AA Gun -artillery_units: - - M12 Gun Motor Carriage -logistics_units: - - Truck GMC "Jimmy" 6x6 Truck -infantry_units: - - Infantry M1 Garand -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Ally Flak - - WW2LST -naval_units: [] -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ -carrier_names: [] -helicopter_carrier_names: [] -has_jtac: false -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II diff --git a/resources/factions/usa_1945.yaml b/resources/factions/usa_1945.yaml deleted file mode 100644 index b04c9dfd1..000000000 --- a/resources/factions/usa_1945.yaml +++ /dev/null @@ -1,108 +0,0 @@ ---- -country: USA -name: USA 1945 -authors: Ghosti -description:

    US army in 1945, Pacific Theater of Operations.

    -locales: - - en_US -aircrafts: - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - P-47D-30 Thunderbolt (Early) - - P-47D-30 Thunderbolt (Late) - - P-47D-40 Thunderbolt - - A-20G Havoc -frontline_units: - - Bofors 40 mm Gun - - M2A1 Half-Track - - M4A2(75) Sherman -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Cold-War-Flak -naval_units: [] -doctrine: ww2 -building_set: ww2free -requirements: {} -liveries_overrides: - A-20G Havoc: - - USAF 645th BS - - USAF 668th BS - P-47D-30 Thunderbolt (Early): - - 53rd_FS_9th_Air_Force - - 61st_FS_8th_AF_HVZ - - 61st_FS_1944 - - 61st_FS_D_day - - 79thFG 86thFS The Trojan Warhorse - - Lt_Col_Benjamin_Mayo - - Lt_Col_Gabreski_1944 - - Lt_Col_Gabreski_D_day - - Maj_Howard_Park_1945 - - TONY 5th Emergency Rescue Squadron - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D28 - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D40 - - USAF Standard - - WarChief - P-47D-30 Thunderbolt (Late): - - 53rd_FS_9th_Air_Force - - 61st_FS_8th_AF_HVZ - - 61st_FS_1944 - - 61st_FS_D_day - - 79thFG 86thFS The Trojan Warhorse - - Lt_Col_Benjamin_Mayo - - Lt_Col_Gabreski_1944 - - Lt_Col_Gabreski_D_day - - Maj_Howard_Park_1945 - - TONY 5th Emergency Rescue Squadron - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D28 - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D40 - - USAF Standard - - WarChief - P-47D-40 Thunderbolt: - - 53rd_FS_9th_Air_Force - - 61st_FS_8th_AF_HVZ - - 61st_FS_1944 - - 61st_FS_D_day - - 79thFG 86thFS The Trojan Warhorse - - Lt_Col_Benjamin_Mayo - - Lt_Col_Gabreski_1944 - - Lt_Col_Gabreski_D_day - - Maj_Howard_Park_1945 - - TONY 5th Emergency Rescue Squadron - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D28 - - USAAF 509th FS, 405th FG, ETO 1944, Chief Ski-U-Mah D40 - - USAF Standard - - WarChief - P-51D-25-NA Mustang: - - USAF 302nd FS, RED TAILS - - USAF 344th FS, IRON ASS - - USAF 363rd FS - - USAF 363rd FS, 357th FG DESERT RAT - - USAF 364th FS - - USAF 364th FS, HURRY HOME HONEY - - USAF 375th FS - - USAF 84th FS - - USAF Big Beautiful Doll - - USAF Ferocious Frankie - - USAF Gentleman Jim - - USAF Miss Velma - P-51D-30-NA Mustang: - - USAF 302nd FS, RED TAILS - - USAF 344th FS, IRON ASS - - USAF 363rd FS - - USAF 363rd FS, 357th FG DESERT RAT - - USAF 364th FS - - USAF 364th FS, HURRY HOME HONEY - - USAF 375th FS - - USAF 84th FS - - USAF Big Beautiful Doll - - USAF Ferocious Frankie - - USAF Gentleman Jim - - USAF Miss Velma diff --git a/resources/factions/usa_1955.yaml b/resources/factions/usa_1955.yaml deleted file mode 100644 index 07b126522..000000000 --- a/resources/factions/usa_1955.yaml +++ /dev/null @@ -1,35 +0,0 @@ ---- -country: USA -name: USA 1955 -authors: Khopa -description:

    US army in the 50s, circa Korean War.

    -locales: - - en_US -aircrafts: - - B-52H Stratofortress - - C-130 - - F-86F Sabre - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang -frontline_units: - - Bofors 40 mm Gun - - M2A1 Half-Track - - M4A2(75) Sherman - - M60A3 "Patton" -artillery_units: - - M12 Gun Motor Carriage -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 -missiles: [] -air_defense_units: - - Bofors 40 mm Gun -preset_groups: - - Cold-War-Flak -naval_units: [] -doctrine: ww2 -building_set: ww2ally -cargo_ship: LST Mk.II -requirements: - WW2 Asset Pack: https://www.digitalcombatsimulator.com/en/products/other/wwii_assets_pack/ diff --git a/resources/factions/usa_1960.yaml b/resources/factions/usa_1960.yaml deleted file mode 100644 index ef7e7a014..000000000 --- a/resources/factions/usa_1960.yaml +++ /dev/null @@ -1,31 +0,0 @@ ---- -country: USA -name: USA 1960 -authors: Khopa -description:

    US army in the 60s, pre-Vietnam war.

    -locales: - - en_US -aircrafts: - - B-52H Stratofortress - - C-130 - - F-86F Sabre - - P-51D-25-NA Mustang - - P-51D-30-NA Mustang - - UH-1H Iroquois -frontline_units: - - M113 - - M163 Vulcan Air Defense System - - M60A3 "Patton" -artillery_units: [] -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 -missiles: [] -air_defense_units: - - M163 Vulcan Air Defense System -preset_groups: - - Cold-War-Flak -naval_units: [] -requirements: {} -doctrine: coldwar diff --git a/resources/factions/usa_1965.yaml b/resources/factions/usa_1965.yaml deleted file mode 100644 index 1a93d5ecb..000000000 --- a/resources/factions/usa_1965.yaml +++ /dev/null @@ -1,43 +0,0 @@ ---- -country: USA -name: USA 1965 -authors: Khopa -description:

    US army in the late 60s, during Vietnam war.

    -locales: - - en_US -aircrafts: - - B-52H Stratofortress - - C-130 - - CH-47D - - F-4E Phantom II - - F-4B Phantom II - - F-4C Phantom II - - F-5E Tiger II - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M163 Vulcan Air Defense System - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -missiles: [] -preset_groups: - - Hawk - - Cold-War-Flak -naval_units: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: {} -doctrine: coldwar diff --git a/resources/factions/usa_1970.yaml b/resources/factions/usa_1970.yaml deleted file mode 100644 index c707e32bf..000000000 --- a/resources/factions/usa_1970.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -country: USA -name: USA 1970 -authors: Starfire -description:

    US military during the Vietnam War from 1965 to 1975

    -locales: - - en_US -aircrafts: - - F-14A Tomcat (Block 135-GR Late) - - F-4C Phantom II - - F-4B Phantom II - - F-4E Phantom II - - F-5E Tiger II - - A-4E Skyhawk - - OV-10A Bronco - - C-101CC Aviojet - - B-52H Stratofortress - - C-47 Skytrain - - C-130 - - UH-1H Iroquois - - AH-1W SuperCobra - - OH-58D Kiowa Warrior - - CH-47D - - CH-53E -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M163 Vulcan Air Defense System - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 - - LARC-V -infantry_units: - - Infantry M249 - - Infantry M4 -missiles: [] -preset_groups: - - Hawk -naval_units: - - FFG Oliver Hazard Perry - - CV-59 Forrestal -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -carrier_names: - - CV-59 Forrestal - - CV-60 Saratoga - - CV-61 Ranger - - CV-62 Independence -requirements: {} -doctrine: coldwar diff --git a/resources/factions/usa_1975.yaml b/resources/factions/usa_1975.yaml deleted file mode 100644 index 88e6c4f52..000000000 --- a/resources/factions/usa_1975.yaml +++ /dev/null @@ -1,52 +0,0 @@ ---- -country: USA -name: USA 1975 -authors: Khopa -description:

    US army in the 70s at the end of the war in Vietnam.

    -locales: - - en_US -aircrafts: - - B-52H Stratofortress - - C-130 - - CH-47D - - CH-53E - - F-14A Tomcat (Block 135-GR Late) - - F-4E Phantom II - - F-4B Phantom II - - F-4C Phantom II - - F-5E Tiger II - - S-3B Viking - - OV-10A Bronco - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - KC-130 - - KC-135 Stratotanker -frontline_units: - - M113 - - M163 Vulcan Air Defense System - - M48 Chaparral - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 -missiles: [] -preset_groups: - - Hawk - - Cold-War-Flak -naval_units: - - FFG Oliver Hazard Perry - - CV-59 Forrestal -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -carrier_names: - - CVN-59 Forrestal -requirements: {} -doctrine: coldwar diff --git a/resources/factions/usa_1990.yaml b/resources/factions/usa_1990.yaml deleted file mode 100644 index 6c932409e..000000000 --- a/resources/factions/usa_1990.yaml +++ /dev/null @@ -1,104 +0,0 @@ ---- -country: USA -name: USA 1990 -authors: Khopa -description:

    US army in the 90s, Gulf War/Desert Storm.

    -locales: - - en_US -aircrafts: - - A-10A Thunderbolt II - - AH-64A Apache - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - CH-47D - - CH-53E - - F-117A Nighthawk - - F-14A Tomcat (Block 135-GR Late) - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F/A-18C Hornet (Lot 20) - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois - - UH-60A - - UH-60L -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-130J - - KC-135 Stratotanker - - S-3B Tanker -frontline_units: - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - M1126 Stryker ICV (M2 HMG) - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Hawk - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger - - M48 Chaparral -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - F/A-18C Hornet (Lot 20): - - VFA-106 - - VFA-113 - - VFA-122 - - VFA-131 - - VFA-192 - - VFA-34 - - VFA-37 - - VFA-83 - - VFA-87 - - VFA-97 - - VMFA-122 - - VMFA-132 - - VMFA-251 - - VMFA-312 - - VMFA-314 - - VMFA-323 diff --git a/resources/factions/usa_2005.yaml b/resources/factions/usa_2005.yaml deleted file mode 100644 index 5a4a7b855..000000000 --- a/resources/factions/usa_2005.yaml +++ /dev/null @@ -1,111 +0,0 @@ ---- -country: USA -name: USA 2005 -authors: Khopa -description:

    USA in the 2000s.

    -locales: - - en_US -aircrafts: - - A-10C Thunderbolt II (Suite 3) - - A-10C Thunderbolt II (Suite 7) - - AH-64D Apache Longbow - - AH-64D Apache Longbow (AI) - - AV-8B Harrier II Night Attack - - B-1B Lancer - - B-52H Stratofortress - - C-130 - - C-130J-30 Super Hercules - - C-17A - - CH-47D - - CH-53E - - F-117A Nighthawk - - F-14B Tomcat - - F-15C Eagle - - F-15E Strike Eagle - - F-15E Strike Eagle (Suite 4+) - - F-16CM Fighting Falcon (Block 50) - - F-22A Raptor - - F/A-18C Hornet (Lot 20) - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois - - UH-60A - - UH-60L -awacs: - - E-2C Hawkeye - - E-3A -tankers: - - KC-130 - - KC-130J - - KC-135 Stratotanker - - KC-135 Stratotanker MPRS - - S-3B Tanker -frontline_units: - - LAV-25 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1097 Heavy HMMWV Avenger - - M1126 Stryker ICV (M2 HMG) - - M1128 Stryker Mobile Gun System - - M1134 Stryker ATGM (BGM-71 TOW) - - M1A2 Abrams - - M2A2 Bradley - - M6 Linebacker -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -preset_groups: - - Patriot - - NASAMS AIM-120C -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - EWR AN/FPS-117 Radar - - M1097 Heavy HMMWV Avenger - - M6 Linebacker - - Centurion C-RAM LPWS -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -liveries_overrides: - F/A-18C Hornet (Lot 20): - - VFA-106 - - VFA-113 - - VFA-122 - - VFA-131 - - VFA-192 - - VFA-34 - - VFA-37 - - VFA-83 - - VFA-87 - - VFA-97 - - VMFA-122 - - VMFA-132 - - VMFA-251 - - VMFA-312 - - VMFA-314 - - VMFA-323 diff --git a/resources/factions/usn_1985.yaml b/resources/factions/usn_1985.yaml deleted file mode 100644 index e34001a1f..000000000 --- a/resources/factions/usn_1985.yaml +++ /dev/null @@ -1,73 +0,0 @@ ---- -country: USA -name: US Navy 1985 -authors: HerrTom -description:

    Highway to the Danger Zone! For Tomcat lovers.

    -locales: - - en_US -aircrafts: - - AH-1W SuperCobra - - A-4E Skyhawk - - F-14A Tomcat (Block 135-GR Late) - - F-14B Tomcat - - F-4B Phantom II - - F-4E Phantom II - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - S-3B Tanker -frontline_units: - - M1043 HMMWV (M2 HMG) - - M113 - - M163 Vulcan Air Defense System - - M60A3 "Patton" -artillery_units: - - M109A6 Paladin - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M249 - - Infantry M4 - - MANPADS Stinger - - Mortar 2B11 120mm -air_defense_units: - - M163 Vulcan Air Defense System - - M48 Chaparral -preset_groups: - - Hawk -naval_units: - - FFG Oliver Hazard Perry - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -requirements: {} -doctrine: coldwar -liveries_overrides: - F/A-18C Hornet (Lot 20): - - VFA-106 - - VFA-113 - - VFA-122 - - VFA-131 - - VFA-192 - - VFA-34 - - VFA-37 - - VFA-83 - - VFA-87 - - VFA-97 diff --git a/resources/factions/usn_2005.yaml b/resources/factions/usn_2005.yaml deleted file mode 100644 index cb5dc2fa2..000000000 --- a/resources/factions/usn_2005.yaml +++ /dev/null @@ -1,76 +0,0 @@ -country: USA -name: US Navy 2005 -authors: Fuzzle -description:

    A modern representation of the US Navy/Marine Corps.

    -locales: - - en_US -aircrafts: - - F-14B Tomcat - - F/A-18C Hornet (Lot 20) - - F/A-18E Super Hornet - - F/A-18F Super Hornet - - AV-8B Harrier II Night Attack - - AH-1W SuperCobra - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - S-3B Tanker -frontline_units: - - M113 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1A2 Abrams - - LAV-25 - - M163 Vulcan Air Defense System -artillery_units: - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 - - Infantry M249 - - MANPADS Stinger -preset_groups: - - Hawk - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -doctrine: modern -liveries_overrides: - F-14B Tomcat: - - VF-142 Ghostriders - F/A-18C Hornet (Lot 20): - - VMFA-251 high visibility - AV-8B Harrier II Night Attack: - - VMAT-542 - AH-1W SuperCobra: - - Marines - UH-1H Iroquois: - - US NAVY diff --git a/resources/factions/usn_2009.yaml b/resources/factions/usn_2009.yaml deleted file mode 100644 index 84d4f1c61..000000000 --- a/resources/factions/usn_2009.yaml +++ /dev/null @@ -1,74 +0,0 @@ -country: USA -name: US Navy 2005 -authors: Fuzzle, Chilli -description:

    A modern representation of the US Navy/Marine Corps.

    -locales: - - en_US -aircrafts: - - F/A-18C Hornet (Lot 20) - - F/A-18E Super Hornet - - F/A-18F Super Hornet - - EA-18G Growler - - AV-8B Harrier II Night Attack - - AH-1W SuperCobra - - S-3B Viking - - SH-60B Seahawk - - UH-1H Iroquois -awacs: - - E-2C Hawkeye -tankers: - - S-3B Tanker -frontline_units: - - M113 - - M1043 HMMWV (M2 HMG) - - M1045 HMMWV (BGM-71 TOW) - - M1A2 Abrams - - LAV-25 - - M163 Vulcan Air Defense System -artillery_units: - - M270 Multiple Launch Rocket System -logistics_units: - - Truck M818 6x6 -infantry_units: - - Infantry M4 - - Infantry M249 - - MANPADS Stinger -preset_groups: - - Hawk - - Patriot -naval_units: - - FFG Oliver Hazard Perry - - DDG Arleigh Burke IIa - - CG Ticonderoga - - LHA-1 Tarawa - - CVN-74 John C. Stennis -missiles: [] -air_defense_units: - - SAM Hawk SR (AN/MPQ-50) - - M163 Vulcan Air Defense System - - M48 Chaparral -requirements: {} -carrier_names: - - CVN-71 Theodore Roosevelt - - CVN-72 Abraham Lincoln - - CVN-73 George Washington - - CVN-74 John C. Stennis - - CVN-75 Harry S. Truman -helicopter_carrier_names: - - LHA-1 Tarawa - - LHA-2 Saipan - - LHA-3 Belleau Wood - - LHA-4 Nassau - - LHA-5 Peleliu -has_jtac: true -jtac_unit: MQ-9 Reaper -doctrine: modern -liveries_overrides: - F/A-18C Hornet (Lot 20): - - VMFA-251 high visibility - AV-8B Harrier II Night Attack: - - VMAT-542 - AH-1W SuperCobra: - - Marines - UH-1H Iroquois: - - US NAVY diff --git a/resources/fonts/Inconsolata.otf b/resources/fonts/Inconsolata.otf deleted file mode 100644 index e7e1fa0cd..000000000 Binary files a/resources/fonts/Inconsolata.otf and /dev/null differ diff --git a/resources/fonts/OFL.txt b/resources/fonts/OFL.txt deleted file mode 100644 index 6fe694fc3..000000000 --- a/resources/fonts/OFL.txt +++ /dev/null @@ -1,38 +0,0 @@ -—————————————————————————————- -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 -—————————————————————————————- - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. - -The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. - -DEFINITIONS -“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. - -“Reserved Font Name” refers to any names specified as such after the copyright statement(s). - -“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s). - -“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. - -“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. - -5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/resources/frontlines/caucasus.json b/resources/frontlines/caucasus.json deleted file mode 100644 index c2f7a80c7..000000000 --- a/resources/frontlines/caucasus.json +++ /dev/null @@ -1 +0,0 @@ -{"28|26": {"points": [[-83519.432788948, 834083.89603137], [-76119.776928765, 743854.15425227], [-69364.629004892, 719860.24185348], [-66223.861015868, 712472.15322055], [-55063.838612323, 701790.55845189], [-51581.840958501, 704161.97484394]], "start_cp": 28}, "32|27": {"points": [[-148553.72718928, 843792.03708555], [-114733.18523211, 848507.87882073], [-93593.960629467, 841634.68667249], [-83721.151431284, 834200.8738046]], "start_cp": 32}, "32|28": {"points": [[-148554.87082704, 843689.04452871], [-114733.18523211, 845562.62834108], [-110339.43457942, 812629.20979521], [-111707.66520572, 785946.43211532], [-119336.17607842, 776106.17954928], [-124839.73032662, 760747.06391035]], "start_cp": 32}, "27|26": {"points": [[-124831.33530722, 760646.27221205], [-100762.17095534, 753347.75031825], [-86615.899059596, 729586.43747856], [-70460.285574716, 694513.4327179], [-50443.346691892, 703139.51687735]], "start_cp": 27}, "26|16": {"points": [[-51128.273849964, 705442.60983569], [-17096.829383992, 583922.76901062], [-9413.0964883513, 489204.29454645], [-26751.202695677, 458085.37842522]], "start_cp": 26}, "16|17": {"points": [[-26290.077082534, 457532.52869133], [-12087.691792587, 444620.30900361], [-9183.8957732278, 411618.86444668], [-19095.485460604, 393640.78914313], [-12512.173613316, 386130.07819866], [-6723.0801746587, 294506.97247323], [8289.1802310393, 267690.0671157], [-1709.4806012567, 249581.13338705], [-20329.725545816, 256364.19845868], [-32338.671748957, 281488.17801525], [-44457.480224214, 298277.60074695], [-50348.762426692, 298378.38229135]], "start_cp": 16}, "17|18": {"points": [[-50428.449268252, 298385.98215495], [-47925.882995864, 299522.84586356], [-47742.307667018, 302423.33605932], [-51670.819704316, 306425.27822816], [-52890.978467907, 309683.60757879], [-52158.285335864, 315248.49431547], [-54476.310454094, 321830.02991902], [-61058.499192715, 325379.38150096], [-61379.264542506, 327677.41312797], [-59644.880081364, 329300.50019054], [-59830.375745657, 332806.36824568], [-63794.637882896, 337172.7521818], [-67470.778941327, 340636.53352785], [-70179.929699705, 341613.85524925], [-69660.171385319, 350494.94296899], [-69388.993134334, 354630.4112965], [-75106.334592587, 354856.39317232], [-76281.440346853, 358652.8886861], [-81388.630740391, 366494.45977706], [-87241.561324136, 371036.69548105], [-89840.352896069, 379895.1850132], [-95874.068980471, 384753.79534334], [-98992.618866791, 390742.31505257], [-105500.89689041, 395510.53263238], [-109975.33803166, 401747.63240502], [-112664.52235392, 406199.47535868], [-118042.89099844, 411623.04037836], [-119433.38420159, 414545.36512974], [-121777.77888263, 415031.75406772], [-125094.95143961, 417580.4321027], [-127809.00171351, 419876.18788994], [-131233.17983685, 423387.91602212], [-134219.60791602, 427162.2941808], [-142354.54855856, 436882.58763511], [-142151.02610079, 439008.26663852], [-144141.02346569, 440738.2075296], [-154337.7160827, 451791.06647059], [-156349.9178749, 457412.78487971], [-161121.11800072, 459238.28753654], [-164180.10148029, 461855.90812217]], "start_cp": 17}, "18|21": {"points": [[-164264.74921603, 462240.8713078], [-170274.83407271, 474599.20385019], [-172409.88129215, 477254.97986699], [-173104.00129217, 479130.75653371], [-174533.55795887, 482196.45320045], [-175268.99462556, 485708.3698672], [-176186.22462558, 487716.35986724], [-177285.24795894, 488666.6432006], [-178400.79795897, 489162.44320061], [-180541.00129235, 490542.41986731], [-183995.07462577, 493831.22653406], [-185517.42530201, 501467.08245066], [-185474.55938496, 507404.01196323], [-187746.45298904, 511540.57295936], [-190489.87168078, 513490.97218551], [-196791.16148834, 516405.85454547]], "start_cp": 18}, "21|20": {"points": [[-196714.42589455, 516411.96814195], [-197450.59049978, 523168.80433533], [-197732.15105425, 528120.95761683], [-197699.02628313, 533768.73109171], [-198311.83454874, 540807.74495336], [-198842.52672667, 546607.07868341], [-199402.89801799, 549442.89703645], [-200896.04977609, 551418.00206698], [-202121.5817902, 551281.83184319], [-202802.43290916, 551962.68296214], [-202604.3671291, 553881.44520647], [-204919.26093354, 558771.19415168], [-207135.12184795, 559043.53459927], [-209821.38899001, 559390.14971437], [-212321.96946326, 561717.42263007], [-214993.578381, 562726.87596614], [-220482.29198081, 564029.17214026]], "start_cp": 21}, "20|23": {"points": [[-220672.07816602, 564666.16009935], [-225466.53293841, 577226.74074072], [-225867.80020827, 582560.25153588], [-226971.28520037, 588278.31013131], [-229011.0604888, 592424.73858648], [-232087.44289102, 595718.47409321], [-233993.46242283, 598192.95559065], [-234745.0795704, 605985.79430519], [-238229.0345155, 610496.39618843], [-245013.37774879, 611843.03758538], [-252127.56713626, 613492.22847069], [-260588.37132113, 620015.44606012], [-270266.03318718, 624574.33114385], [-274285.71028992, 632588.96571051], [-278888.32106515, 640507.86809234], [-281561.45308744, 647019.85888349]], "start_cp": 20}, "23|24": {"points": [[-281730.7296916, 647253.59774005], [-290982.81972459, 649906.82826413], [-294663.23013322, 650003.68116962], [-298488.96273308, 642238.09370951], [-301465.17238261, 635293.60452728], [-305217.78454941, 628521.64923777], [-309876.19965302, 626882.57725687], [-316044.28631799, 627745.2467205], [-318472.62171129, 628904.60667428], [-317887.74401676, 635471.94764428]], "start_cp": 23}, "24|25": {"points": [[-317873.22860422, 635639.0650959], [-312899.88159494, 646184.05618911], [-306709.82545376, 651773.13600592], [-302953.72342634, 651502.69665994], [-299948.8418044, 651262.30613019], [-297935.57111771, 652704.64930872], [-296162.69096076, 656130.21435772], [-295856.9172118, 663129.98092517], [-295423.18658872, 668374.17845869], [-293700.92883347, 671849.09769727], [-290615.92415898, 672244.90961777], [-288066.42972986, 674165.76158491], [-286820.78633299, 677600.01207161], [-286893.79300875, 679835.68894319], [-286618.90964092, 682436.5085003], [-285244.4928018, 683705.20096718]], "start_cp": 24}, "25|23": {"points": [[-284669.68592925, 683920.85836338], [-284033.62440161, 671710.30738432], [-284533.77033624, 669857.91503381], [-285774.87321108, 669765.29541629], [-288423.79427231, 670358.06096845], [-288982.2616923, 669926.15330961], [-288459.09137937, 667542.82188402], [-285718.97087515, 657267.36992099], [-281630.5138127, 647419.52117057]], "start_cp": 25}, "25|31": {"points": [[-284263.99293597, 684700.54580073], [-272604.87474782, 700374.86510124], [-273331.93020798, 704467.91806214], [-277532.6950889, 709395.73840322], [-281410.32420975, 715562.24582457], [-282763.16813743, 718965.99542922], [-284038.34156377, 723212.87736217], [-285647.59520339, 726629.3333984], [-286742.41427361, 730713.85069882], [-290637.44365803, 734503.60901881], [-294658.79831979, 742062.07144589], [-297037.92437623, 747430.89573254], [-299143.34566511, 751157.49141386], [-299648.64677444, 755747.30982361], [-297543.22548556, 760400.29087204], [-293500.81661091, 766927.09686757], [-290805.87736114, 772043.27059955], [-294728.00259664, 779192.46248204], [-289131.68727782, 794537.19803365], [-284302.60873658, 803382.98676341], [-286153.0033178, 818998.51176593], [-283670.76668445, 834568.9051933], [-290756.42398328, 855871.00866495], [-293497.37680705, 872691.40288022], [-298728.59569045, 876959.26028386], [-299033.75480734, 883966.6044418], [-299055.28124949, 884675.04815429], [-299818.06111468, 885322.52382059], [-308456.45796809, 893001.69982944], [-311598.60162174, 897764.58963223], [-312216.79613588, 902058.30176963], [-312264.20281806, 902423.79800646], [-312738.11562308, 902452.63317662], [-318952.43355462, 903032.81497309]], "start_cp": 25}, "31|32": {"points": [[-319413.50770939, 903161.13927527], [-312671.27979139, 903060.83924503], [-312324.50415159, 903053.25482189], [-312203.42896954, 902599.67200635], [-311123.51486173, 897768.90194652], [-308519.80029013, 892811.99843776], [-299725.00782398, 885575.0970382], [-298905.33045141, 884872.77713154], [-298821.06157145, 884019.77775077], [-298298.35634543, 877006.39271804], [-291393.57547003, 873411.8434301], [-288926.34291968, 873766.98136965], [-273396.69812304, 873213.96162732], [-272951.29274537, 873210.63633871], [-272449.20605747, 873723.537192], [-262767.79330839, 883418.21980792], [-255300.09049795, 886097.47196129], [-240022.65268728, 889745.81531906], [-225543.28998612, 892596.08356732], [-218724.28531507, 888448.82017709], [-215656.78759916, 883416.20673693], [-214086.63445796, 873664.97864894], [-221406.94515152, 861563.14860602], [-218652.16733902, 855560.98269335], [-218619.81218872, 855140.36573947], [-218296.26068574, 855027.12271343], [-211841.78700129, 853553.62800841], [-206210.96305046, 853832.24537185], [-200950.59208156, 852508.09558384], [-194072.72704603, 852086.25319499], [-191404.28495595, 852694.64158494], [-188982.449823, 852694.64158494], [-186034.22200645, 852522.66532349], [-183530.30158366, 851166.88402139], [-180342.38338683, 851032.52731578], [-178180.46185106, 851948.59576314], [-175212.40008161, 852779.16448874], [-171877.91093321, 852962.37817822], [-167460.79156926, 854118.55241154], [-163919.58243455, 854146.2181079], [-159410.07392707, 852181.95366599], [-155370.88225779, 848557.74744219], [-151193.36210669, 845265.52957477], [-148897.1093084, 843799.24766743]], "start_cp": 31}} \ No newline at end of file diff --git a/resources/groups/Ally-Flak.yaml b/resources/groups/Ally-Flak.yaml deleted file mode 100644 index a53857b3e..000000000 --- a/resources/groups/Ally-Flak.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: Ally Flak -tasks: - - AAA -units: - - QF 3.7-inch AA Gun - - M1 37mm Gun - - M45 Quadmount - - Willys Jeep - - M30 Cargo Carrier - - M4 High-Speed Tractor - - Truck Bedford -layouts: - - WW2 Ally Flak Site \ No newline at end of file diff --git a/resources/groups/Carrier_Strike_Group_8.yaml b/resources/groups/Carrier_Strike_Group_8.yaml deleted file mode 100644 index d91d6948f..000000000 --- a/resources/groups/Carrier_Strike_Group_8.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: Carrier Strike Group 8 -tasks: - - Navy -units: - - CVN-74 John C. Stennis - - DDG Arleigh Burke IIa - - CG Ticonderoga -layouts: - - Carrier Strike Group 8 \ No newline at end of file diff --git a/resources/groups/Chinese-Navy.yaml b/resources/groups/Chinese-Navy.yaml deleted file mode 100644 index 629a20b59..000000000 --- a/resources/groups/Chinese-Navy.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: Chinese Navy -tasks: - - Navy -units: - - Type 052C Destroyer - - Type 052B Destroyer - - Type 054A Frigate -layouts: - - Naval Group \ No newline at end of file diff --git a/resources/groups/Cold-War-Flak.yaml b/resources/groups/Cold-War-Flak.yaml deleted file mode 100644 index 5b44a1015..000000000 --- a/resources/groups/Cold-War-Flak.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Cold-War-Flak -tasks: - - AAA -units: - - 8.8 cm Flak 18 - - S-60 57mm -layouts: - - Cold War Flak Site \ No newline at end of file diff --git a/resources/groups/Flak.yaml b/resources/groups/Flak.yaml deleted file mode 100644 index 5cf59d3c0..000000000 --- a/resources/groups/Flak.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Flak -tasks: - - AAA -units: - - 2 cm Flakvierling 38 - - 8.8 cm Flak 18 - - 8.8 cm Flak 36 - - 8.8 cm Flak 37 - - 8.8 cm Flak 41 - - 2 cm Flak 38 - - SL Flakscheinwerfer 37 - - PU Maschinensatz_33 - - AAA SP Kdo.G.40 - - LUV Kubelwagen 82 - - Truck Opel Blitz -layouts: - - Flak Site \ No newline at end of file diff --git a/resources/groups/Freya.yaml b/resources/groups/Freya.yaml deleted file mode 100644 index d64a5cbb5..000000000 --- a/resources/groups/Freya.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: Freya -tasks: - - SHORAD -units: - - EWR FuMG-401 Freya LZ - - 2 cm Flakvierling 38 - - 8.8 cm Flak 18 - - LUV Kubelwagen 82 - - Sd.Kfz.7 Tractor - - LUV Kettenrad - - PU Maschinensatz_33 - - AAA SP Kdo.G.40 - - Infantry Mauser 98 -layouts: - - Freya EWR Site \ No newline at end of file diff --git a/resources/groups/HQ-2.yaml b/resources/groups/HQ-2.yaml deleted file mode 100644 index 362109353..000000000 --- a/resources/groups/HQ-2.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: HQ-2 -tasks: - - MERAD -units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-2 S-75 "Fan Song" TR - - SAM HQ-2 LN SM-90 -layouts: - - 4 Launcher Site (Semicircle) - - 4 Launcher Site (Circle) diff --git a/resources/groups/HQ-7.yaml b/resources/groups/HQ-7.yaml deleted file mode 100644 index 81273a12d..000000000 --- a/resources/groups/HQ-7.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: HQ-7 -tasks: - - SHORAD -units: - - HQ-7 Self-Propelled STR - - HQ-7 Launcher -layouts: - - 4 Launcher Site (Semicircle) \ No newline at end of file diff --git a/resources/groups/Hawk.yaml b/resources/groups/Hawk.yaml deleted file mode 100644 index a09988dee..000000000 --- a/resources/groups/Hawk.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: Hawk -tasks: - - MERAD -units: - - SAM Hawk SR (AN/MPQ-50) - - SAM Hawk Platoon Command Post (PCP) - - SAM Hawk TR (AN/MPQ-46) - - SAM Hawk LN M192 -layouts: - - 6 Launcher Site (Semicircle) \ No newline at end of file diff --git a/resources/groups/KS-19.yaml b/resources/groups/KS-19.yaml deleted file mode 100644 index a5cdb1ff8..000000000 --- a/resources/groups/KS-19.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: KS-19 -tasks: - - AAA -units: - - AAA SON-9 Fire Can - - AAA 100mm KS-19 -layouts: - - AAA Site \ No newline at end of file diff --git a/resources/groups/NASAMS-B.yaml b/resources/groups/NASAMS-B.yaml deleted file mode 100644 index aba445527..000000000 --- a/resources/groups/NASAMS-B.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: NASAMS AIM-120B -tasks: - - MERAD -units: - - SAM NASAMS C2 - - SAM NASAMS SR MPQ64F1 - - SAM NASAMS LN AIM-120B -layouts: - - 4 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/NASAMS-C.yaml b/resources/groups/NASAMS-C.yaml deleted file mode 100644 index e8e82913e..000000000 --- a/resources/groups/NASAMS-C.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: NASAMS AIM-120C -tasks: - - MERAD -units: - - SAM NASAMS C2 - - SAM NASAMS SR MPQ64F1 - - SAM NASAMS LN AIM-120C -layouts: - - 4 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/Patriot.yaml b/resources/groups/Patriot.yaml deleted file mode 100644 index 8581c77bc..000000000 --- a/resources/groups/Patriot.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: Patriot -tasks: - - LORAD -units: - - SAM Patriot STR - - SAM Patriot CR (AMG AN/MRC-137) - - SAM Patriot ECS - - SAM Patriot C2 ICC - - SAM Patriot EPP-III - - SAM Patriot LN -layouts: - - Patriot Battery \ No newline at end of file diff --git a/resources/groups/Rapier.yaml b/resources/groups/Rapier.yaml deleted file mode 100644 index 27de9179c..000000000 --- a/resources/groups/Rapier.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: Rapier -tasks: - - SHORAD -units: - - SAM Rapier Blindfire TR - - SAM Rapier Tracker - - SAM Rapier LN -layouts: - - 2 Launcher Site \ No newline at end of file diff --git a/resources/groups/Roland.yaml b/resources/groups/Roland.yaml deleted file mode 100644 index 047777ccc..000000000 --- a/resources/groups/Roland.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Roland -tasks: - - SHORAD -units: - - SAM Roland EWR - - Roland 2 (Marder Chassis) -layouts: - - 2 Launcher Site \ No newline at end of file diff --git a/resources/groups/Russian-Navy.yaml b/resources/groups/Russian-Navy.yaml deleted file mode 100644 index afe7a19a7..000000000 --- a/resources/groups/Russian-Navy.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: Russian Navy -tasks: - - Navy -units: - - Corvette 1124.4 Grish - - Corvette 1241.1 Molniya - - Frigate 11540 Neustrashimy - - Frigate 1135M Rezky - - Cruiser 1164 Moskva -layouts: - - Naval Group \ No newline at end of file diff --git a/resources/groups/SA-10.yaml b/resources/groups/SA-10.yaml deleted file mode 100644 index 4619acccf..000000000 --- a/resources/groups/SA-10.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: SA-10/S-300PS -tasks: - - LORAD -units: - - SAM SA-10 S-300 "Grumble" Clam Shell SR - - SAM SA-10 S-300 "Grumble" Big Bird SR - - SAM SA-10 S-300 "Grumble" C2 - - SAM SA-10 S-300 "Grumble" Flap Lid TR - - SAM SA-10 S-300 "Grumble" TEL D - - SAM SA-10 S-300 "Grumble" TEL C -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-10B.yaml b/resources/groups/SA-10B.yaml deleted file mode 100644 index 0194d155d..000000000 --- a/resources/groups/SA-10B.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: SA-10B/S-300PS -tasks: - - LORAD -units: - - SAM SA-10B S-300PS 40B6MD SR - - SAM SA-10B S-300PS 64H6E SR - - SAM SA-10B S-300PS 54K6 CP - - SAM SA-10B S-300PS 30N6 TR - - SAM SA-10B S-300PS 5P85SE LN - - SAM SA-10B S-300PS 5P85SU LN -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-11.yaml b/resources/groups/SA-11.yaml deleted file mode 100644 index ba92f4a41..000000000 --- a/resources/groups/SA-11.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: SA-11 -tasks: - - MERAD -units: - - SAM SA-11 Buk "Gadfly" Snow Drift SR - - SAM SA-11 Buk "Gadfly" C2 - - SAM SA-11 Buk "Gadfly" Fire Dome TEL -layouts: - - 4 Launcher Site (Semicircle) \ No newline at end of file diff --git a/resources/groups/SA-12.yaml b/resources/groups/SA-12.yaml deleted file mode 100644 index 3f20b75d4..000000000 --- a/resources/groups/SA-12.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: SA-12/S-300V -tasks: - - LORAD -units: - - SAM SA-12 S-300V 9S15 SR - - SAM SA-12 S-300V 9S19 SR - - SAM SA-12 S-300V 9S457 CP - - SAM SA-12 S-300V 9S32 TR - - SAM SA-12 S-300V 9A82 LN - - SAM SA-12 S-300V 9A83 LN -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-17.yaml b/resources/groups/SA-17.yaml deleted file mode 100644 index b90b46da3..000000000 --- a/resources/groups/SA-17.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: SA-17 -tasks: - - MERAD -units: - - SAM SA-11 Buk "Gadfly" Snow Drift SR - - SAM SA-11 Buk "Gadfly" C2 - - SAM SA-17 Buk M1-2 LN 9A310M1-2 -layouts: - - 4 Launcher Site (Semicircle) \ No newline at end of file diff --git a/resources/groups/SA-2.yaml b/resources/groups/SA-2.yaml deleted file mode 100644 index 02e538c00..000000000 --- a/resources/groups/SA-2.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: SA-2/S-75 -tasks: - - MERAD -units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-2 S-75 "Fan Song" TR - - SAM SA-2 S-75 "Guideline" LN -layouts: - - 6 Launcher Site (Semicircle) - - 6 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/SA-20.yaml b/resources/groups/SA-20.yaml deleted file mode 100644 index e5d9b84c2..000000000 --- a/resources/groups/SA-20.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: SA-20/S-300PMU-1 -tasks: - - LORAD -units: - - SAM SA-20 S-300PMU1 SR 5N66E - - SAM SA-20 S-300PMU1 SR 64N6E - - SAM SA-20 S-300PMU1 CP 54K6 - - SAM SA-20 S-300PMU1 TR 30N6E - - SAM SA-20 S-300PMU1 LN 5P85CE - - SAM SA-20 S-300PMU1 LN 5P85DE -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-20B.yaml b/resources/groups/SA-20B.yaml deleted file mode 100644 index 82e74289b..000000000 --- a/resources/groups/SA-20B.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: SA-20B/S-300PMU-2 -tasks: - - LORAD -units: - - SAM SA-20 S-300PMU1 SR 5N66E - - SAM SA-20 S-300PMU1 SR 64N6E - - SAM SA-20B S-300PMU2 CP 54K6E2 - - SAM SA-20B S-300PMU2 TR 92H6E(truck) - - SAM SA-20B S-300PMU2 LN 5P85SE2 -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-23.yaml b/resources/groups/SA-23.yaml deleted file mode 100644 index e6439299f..000000000 --- a/resources/groups/SA-23.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: SA-23/S-300VM -tasks: - - LORAD -units: - - SAM SA-23 S-300VM 9S15M2 SR - - SAM SA-23 S-300VM 9S19M2 SR - - SAM SA-23 S-300VM 9S457ME CP - - SAM SA-23 S-300VM 9S32ME TR - - SAM SA-23 S-300VM 9A82ME LN - - SAM SA-23 S-300VM 9A83ME LN -layouts: - - S-300 Site \ No newline at end of file diff --git a/resources/groups/SA-2_high_digit_sam.yaml b/resources/groups/SA-2_high_digit_sam.yaml deleted file mode 100644 index a6745f74b..000000000 --- a/resources/groups/SA-2_high_digit_sam.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: SA-2/S-75 V-759/5V23 -tasks: - - MERAD -units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-2 S-75 "Fan Song" TR - - SAM SA-2 (V759) LN SM-90 -layouts: - - 6 Launcher Site (Semicircle) - - 6 Launcher Site (Circle) diff --git a/resources/groups/SA-3.yaml b/resources/groups/SA-3.yaml deleted file mode 100644 index af943e537..000000000 --- a/resources/groups/SA-3.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: SA-3/S-125 -tasks: - - MERAD -units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-3 S-125 "Low Blow" TR - - SAM SA-3 S-125 "Goa" LN -layouts: - - 4 Launcher Site (Semicircle) - - 4 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/SA-3_high_digit_sam.yaml b/resources/groups/SA-3_high_digit_sam.yaml deleted file mode 100644 index d5ae0bfac..000000000 --- a/resources/groups/SA-3_high_digit_sam.yaml +++ /dev/null @@ -1,10 +0,0 @@ -name: SA-3/S-125 V-601P/5V27 -tasks: - - MERAD -units: - - SAM P19 "Flat Face" SR (SA-2/3) - - SAM SA-3 S-125 "Low Blow" TR - - SAM SA-3 (V-601P) LN 5P73 -layouts: - - 4 Launcher Site (Semicircle) - - 4 Launcher Site (Circle) diff --git a/resources/groups/SA-5.yaml b/resources/groups/SA-5.yaml deleted file mode 100644 index cfbcdc4dd..000000000 --- a/resources/groups/SA-5.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: SA-5/S-200 -tasks: - - LORAD -units: - - SAM SA-5 S-200 ST-68U "Tin Shield" SR - - SAM SA-5 S-200 "Square Pair" TR" - - SAM SA-5 S-200 "Gammon" LN" -layouts: - - 6 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/SA-6.yaml b/resources/groups/SA-6.yaml deleted file mode 100644 index 6065da077..000000000 --- a/resources/groups/SA-6.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: SA-6 -tasks: - - MERAD -units: - - SAM SA-6 Kub "Straight Flush" STR - - SAM SA-6 Kub "Gainful" TEL -layouts: - - 4 Launcher Site (Circle) \ No newline at end of file diff --git a/resources/groups/Silkworm.yaml b/resources/groups/Silkworm.yaml deleted file mode 100644 index f77f2c340..000000000 --- a/resources/groups/Silkworm.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: Silkworm -tasks: - - Coastal -units: - - AShM SS-N-2 Silkworm - - AShM Silkworm SR -layouts: - - Silkworm \ No newline at end of file diff --git a/resources/groups/WW2LST.yaml b/resources/groups/WW2LST.yaml deleted file mode 100644 index e2e1e1151..000000000 --- a/resources/groups/WW2LST.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: WW2LST -tasks: - - Navy -units: - - LS Samuel Chase - - LST Mk.II -layouts: - - WW2 LST Group \ No newline at end of file diff --git a/resources/icon.ico b/resources/icon.ico deleted file mode 100644 index 733e3be98..000000000 Binary files a/resources/icon.ico and /dev/null differ diff --git a/resources/icon.png b/resources/icon.png deleted file mode 100644 index 86fd7e1a5..000000000 Binary files a/resources/icon.png and /dev/null differ diff --git a/resources/layouts/anti_air/2_Launcher.miz b/resources/layouts/anti_air/2_Launcher.miz deleted file mode 100644 index 18dd027f1..000000000 Binary files a/resources/layouts/anti_air/2_Launcher.miz and /dev/null differ diff --git a/resources/layouts/anti_air/2_Launcher.yaml b/resources/layouts/anti_air/2_Launcher.yaml deleted file mode 100644 index 2e5293b4e..000000000 --- a/resources/layouts/anti_air/2_Launcher.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: 2 Launcher Site -tasks: - - SHORAD - - MERAD -groups: - - SAM: - - name: Search Radar - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: Track Radar - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - TrackRadar - - name: Optical Tracker - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - OpticalTracker - - name: Launcher - unit_count: - - 2 - unit_classes: - - SHORAD - - Launcher - - name: Logistics - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - Logistics diff --git a/resources/layouts/anti_air/4_Launcher_Circle.yaml b/resources/layouts/anti_air/4_Launcher_Circle.yaml deleted file mode 100644 index 5d3a87415..000000000 --- a/resources/layouts/anti_air/4_Launcher_Circle.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: 4 Launcher Site (Circle) -tasks: - - MERAD - - LORAD -groups: - - SAM: - - name: Search Radar - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: Track Radar - optional: true # Allow groups without TR - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - TrackRadar - - name: Command Post - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - CommandPost - - name: Launcher - unit_count: - - 4 - unit_classes: - - Launcher - - TELAR - - name: Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics - - PD: # Point Defense as separate group - - name: PD - sub_task: PointDefense - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - SHORAD - - name: AAA - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA -layout_file: resources/layouts/anti_air/8_Launcher_Circle.miz diff --git a/resources/layouts/anti_air/4_Launcher_Semicircle.yaml b/resources/layouts/anti_air/4_Launcher_Semicircle.yaml deleted file mode 100644 index 9f6668c76..000000000 --- a/resources/layouts/anti_air/4_Launcher_Semicircle.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: 4 Launcher Site (Semicircle) -tasks: - - MERAD - - LORAD -groups: - - SAM: # Main Battery as one group - - name: Search Radar - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: Track Radar - optional: true # Allow groups without TR - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - TrackRadar - - name: Command Post - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - CommandPost - - name: Launcher - unit_count: - - 4 - unit_classes: - - Launcher - - TELAR - - name: Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics - - PD: # Point Defense as separate group - - name: PD - sub_task: PointDefense - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - SHORAD - - name: AAA - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA -layout_file: resources/layouts/anti_air/6_Launcher_Semicircle.miz \ No newline at end of file diff --git a/resources/layouts/anti_air/6_Launcher_Circle.miz b/resources/layouts/anti_air/6_Launcher_Circle.miz deleted file mode 100644 index 731c9e91b..000000000 Binary files a/resources/layouts/anti_air/6_Launcher_Circle.miz and /dev/null differ diff --git a/resources/layouts/anti_air/6_Launcher_Circle.yaml b/resources/layouts/anti_air/6_Launcher_Circle.yaml deleted file mode 100644 index 7a3c41056..000000000 --- a/resources/layouts/anti_air/6_Launcher_Circle.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: 6 Launcher Site (Circle) -tasks: - - MERAD - - LORAD -groups: - - SAM: # Main Battery as one group - - name: Search Radar - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: Track Radar - optional: true # Allow groups without TR - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - TrackRadar - - name: Command Post - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - CommandPost - - name: Launcher - unit_count: - - 6 - unit_classes: - - Launcher - - TELAR - - name: Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics - - PD: # Point Defense as separate group - - name: PD - sub_task: PointDefense - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - SHORAD - - name: AAA - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA -layout_file: resources/layouts/anti_air/6_Launcher_Circle.miz diff --git a/resources/layouts/anti_air/6_Launcher_Semicircle.miz b/resources/layouts/anti_air/6_Launcher_Semicircle.miz deleted file mode 100644 index 3ecc8d48f..000000000 Binary files a/resources/layouts/anti_air/6_Launcher_Semicircle.miz and /dev/null differ diff --git a/resources/layouts/anti_air/6_Launcher_Semicircle.yaml b/resources/layouts/anti_air/6_Launcher_Semicircle.yaml deleted file mode 100644 index 9b6a859f5..000000000 --- a/resources/layouts/anti_air/6_Launcher_Semicircle.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: 6 Launcher Site (Semicircle) -tasks: - - MERAD - - LORAD -groups: - - SAM: # Main Battery as one group - - name: Search Radar - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: Track Radar - optional: true # Allow groups without TR - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - TrackRadar - - name: Command Post - optional: true - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - CommandPost - - name: Launcher - unit_count: - - 6 - unit_classes: - - Launcher - - TELAR - - name: Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics - - PD: # Point Defense as separate group - - name: PD - sub_task: PointDefense - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - SHORAD - - name: AAA - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA -layout_file: resources/layouts/anti_air/6_Launcher_Semicircle.miz diff --git a/resources/layouts/anti_air/8_Launcher_Circle.miz b/resources/layouts/anti_air/8_Launcher_Circle.miz deleted file mode 100644 index 67541972f..000000000 Binary files a/resources/layouts/anti_air/8_Launcher_Circle.miz and /dev/null differ diff --git a/resources/layouts/anti_air/AAA_Site.miz b/resources/layouts/anti_air/AAA_Site.miz deleted file mode 100644 index e1388235a..000000000 Binary files a/resources/layouts/anti_air/AAA_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/AAA_Site.yaml b/resources/layouts/anti_air/AAA_Site.yaml deleted file mode 100644 index 08e21d832..000000000 --- a/resources/layouts/anti_air/AAA_Site.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: AAA Site -description: A standard AAA template -generic: true -tasks: - - AAA -groups: - - AAA: - - name: AAA Site Radar - optional: true # Optional if the AAA Site has a Radar - fill: false # Do not fill if no Radar is required! - unit_count: - - 1 - unit_classes: - - SearchRadar - - SearchTrackRadar - - name: AAA Site - unit_count: - - 2 - - 6 - unit_classes: - - AAA - - name: AAA Site Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics diff --git a/resources/layouts/anti_air/Cold_War_Flak_Site.miz b/resources/layouts/anti_air/Cold_War_Flak_Site.miz deleted file mode 100644 index 64b2b98b2..000000000 Binary files a/resources/layouts/anti_air/Cold_War_Flak_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/Cold_War_Flak_Site.yaml b/resources/layouts/anti_air/Cold_War_Flak_Site.yaml deleted file mode 100644 index 5fcb82837..000000000 --- a/resources/layouts/anti_air/Cold_War_Flak_Site.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Cold War Flak Site -tasks: - - AAA -groups: - - AAA: - - name: Cold War Flak Site Radar - optional: true # Only available to Late Cold War - fill: false # Do not fill with faction possible units - unit_count: - - 1 - unit_classes: - - SearchRadar - - name: Cold War Flak Site Flak - unit_count: - - 4 - - 6 - unit_types: - - flak18 - - name: Cold War Flak Site S-60 - unit_count: - - 2 - unit_types: - - S-60_Type59_Artillery - - name: Cold War Flak Site AAA - optional: true - unit_count: - - 2 - unit_classes: - - AAA - - name: Cold War Flak Site Logistics - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics diff --git a/resources/layouts/anti_air/Early-Warning_Radar.miz b/resources/layouts/anti_air/Early-Warning_Radar.miz deleted file mode 100644 index 510d5f099..000000000 Binary files a/resources/layouts/anti_air/Early-Warning_Radar.miz and /dev/null differ diff --git a/resources/layouts/anti_air/Early-Warning_Radar.yaml b/resources/layouts/anti_air/Early-Warning_Radar.yaml deleted file mode 100644 index f3b7f8321..000000000 --- a/resources/layouts/anti_air/Early-Warning_Radar.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: Early-Warning Radar -generic: true -tasks: - - EarlyWarningRadar -groups: - - EWR: - - name: Early-Warning Radar 0 - unit_count: - - 1 - unit_classes: - - EarlyWarningRadar - fallback_classes: - - SearchRadar - - SearchTrackRadar diff --git a/resources/layouts/anti_air/Flak_Site.miz b/resources/layouts/anti_air/Flak_Site.miz deleted file mode 100644 index 7fa432ad5..000000000 Binary files a/resources/layouts/anti_air/Flak_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/Flak_Site.yaml b/resources/layouts/anti_air/Flak_Site.yaml deleted file mode 100644 index 362b1c33a..000000000 --- a/resources/layouts/anti_air/Flak_Site.yaml +++ /dev/null @@ -1,50 +0,0 @@ -name: Flak Site -tasks: - - AAA -groups: - - Flak: - - name: Flak Site 0 - unit_count: - - 4 - unit_types: - - flak38 - - flak18 - - flak36 - - flak37 - - flak41 - - flak30 - - name: Flak Site 1 - unit_count: - - 1 - unit_types: - - flak38 - - name: Flak Site 2 - unit_count: - - 1 - unit_types: - - flak36 - - name: Flak Site 3 - unit_count: - - 2 - unit_types: - - Flakscheinwerfer_37 - - name: Flak Site 4 - unit_count: - - 1 - unit_types: - - Maschinensatz_33 - - name: Flak Site 5 - unit_count: - - 1 - unit_types: - - KDO_Mod40 - - name: Flak Site 6 - unit_count: - - 1 - unit_types: - - Kubelwagen_82 - - name: Flak Site 7 - unit_count: - - 4 - unit_types: - - Blitz_36-6700A diff --git a/resources/layouts/anti_air/Freya_EWR_Site.miz b/resources/layouts/anti_air/Freya_EWR_Site.miz deleted file mode 100644 index 3e966ba7d..000000000 Binary files a/resources/layouts/anti_air/Freya_EWR_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/Freya_EWR_Site.yaml b/resources/layouts/anti_air/Freya_EWR_Site.yaml deleted file mode 100644 index f0cc0aa31..000000000 --- a/resources/layouts/anti_air/Freya_EWR_Site.yaml +++ /dev/null @@ -1,50 +0,0 @@ -name: Freya EWR Site -tasks: - - SHORAD -groups: - - Freya: - - name: Freya EWR Site 0 - unit_count: - - 1 - unit_types: - - FuMG-401 - - name: Freya EWR Site 1 - unit_count: - - 4 - unit_types: - - flak38 - - name: Freya EWR Site 2 - unit_count: - - 4 - unit_types: - - flak18 - - name: Freya EWR Site 3 - unit_count: - - 1 - unit_types: - - Kubelwagen_82 - - name: Freya EWR Site 4 - unit_count: - - 1 - unit_types: - - Sd_Kfz_7 - - name: Freya EWR Site 5 - unit_count: - - 1 - unit_types: - - Sd_Kfz_2 - - name: Freya EWR Site 6 - unit_count: - - 1 - unit_types: - - Maschinensatz_33 - - name: Freya EWR Site 7 - unit_count: - - 1 - unit_types: - - KDO_Mod40 - - name: Freya EWR Site 8 - unit_count: - - 3 - unit_types: - - soldier_mauser98 diff --git a/resources/layouts/anti_air/Patriot_Battery.miz b/resources/layouts/anti_air/Patriot_Battery.miz deleted file mode 100644 index 9ad0b43bc..000000000 Binary files a/resources/layouts/anti_air/Patriot_Battery.miz and /dev/null differ diff --git a/resources/layouts/anti_air/Patriot_Battery.yaml b/resources/layouts/anti_air/Patriot_Battery.yaml deleted file mode 100644 index 41f624272..000000000 --- a/resources/layouts/anti_air/Patriot_Battery.yaml +++ /dev/null @@ -1,52 +0,0 @@ -name: Patriot Battery -tasks: - - LORAD -groups: - - Patriot: - - name: Patriot Battery 0 - unit_count: - - 2 - unit_types: - - Patriot str - - name: Patriot Battery 1 - unit_count: - - 1 - unit_types: - - Patriot AMG - - name: Patriot Battery 2 - unit_count: - - 1 - unit_types: - - Patriot ECS - - name: Patriot Battery 3 - unit_count: - - 1 - unit_types: - - Patriot cp - - name: Patriot Battery 4 - unit_count: - - 1 - unit_types: - - Patriot EPP - - name: Patriot Battery 5 - unit_count: - - 8 - unit_types: - - Patriot ln - - PD: - - name: Patriot Battery 7 - optional: true - sub_task: PointDefense - unit_count: - - 1 - - 2 - unit_classes: - - SHORAD - - name: Patriot Battery 6 - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA diff --git a/resources/layouts/anti_air/S-300_Site.miz b/resources/layouts/anti_air/S-300_Site.miz deleted file mode 100644 index b223c5f31..000000000 Binary files a/resources/layouts/anti_air/S-300_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/S-300_Site.yaml b/resources/layouts/anti_air/S-300_Site.yaml deleted file mode 100644 index db3b5166d..000000000 --- a/resources/layouts/anti_air/S-300_Site.yaml +++ /dev/null @@ -1,88 +0,0 @@ -name: S-300 Site -tasks: - - LORAD -groups: - - S-300: - - name: S-300 Site SR1 - unit_count: - - 1 - unit_types: - - S-300PS 40B6MD sr # SA-10 - - S-300PS SA-10B 40B6MD MAST sr # SA-10B - - S-300V 9S15 sr # SA-12 - - S-300PMU1 40B6MD sr # SA-20 + B, is the 5N66E - - S-300VM 9S15M2 sr # SA-23 - - name: S-300 Site SR2 - unit_count: - - 1 - unit_types: - - S-300PS 64H6E sr # SA-10 - - S-300PS 64H6E TRAILER sr # SA-10B - - S-300V 9S19 sr # SA-12 - - S-300PMU1 64N6E sr # SA-20 + B - - S-300VM 9S19M2 sr # SA-23 - - name: S-300 Site CP - unit_count: - - 1 - unit_types: - - S-300PS 54K6 cp # SA-10 - - S-300PS SA-10B 54K6 cp # SA-10B - - S-300V 9S457 cp # SA-12 - - S-300PMU1 54K6 cp # SA-20 - - S-300PMU2 54K6E2 cp # SA-20B - - S-300VM 9S457ME cp # SA-23 - - name: S-300 Site TR - unit_count: - - 1 - unit_types: - - S-300PS 40B6M tr # SA-10 - - S-300PS 30N6 TRAILER tr # SA-10B - - S-300V 9S32 tr # SA-12 - - S-300PMU1 40B6M tr # SA-20, is the 30N6E! - - S-300PMU2 92H6E tr # SA-20B - - S-300VM 9S32ME tr # SA-23 - - name: S-300 Site LN1 - unit_count: - - 3 - unit_types: - - S-300PS 5P85C ln # SA-10 - - S-300PS 5P85SE_mod ln # SA-10B - - S-300V 9A82 ln # SA-12 - - S-300PMU1 5P85CE ln # SA-20 - - S-300PMU2 5P85SE2 ln # SA-20B - - S-300VM 9A82ME ln # SA-23 - - name: S-300 Site LN2 - unit_count: - - 3 - unit_types: - - S-300PS 5P85D ln # SA-10 - - S-300PS 5P85SU_mod ln # SA-10B - - S-300V 9A83 ln # SA-12 - - S-300PMU1 5P85DE ln # SA-20 - - S-300PMU2 5P85SE2 ln # SA-20B - - S-300VM 9A83ME ln # SA-23 - - PD: - - name: S-300 Site SHORAD1 - optional: true - sub_task: PointDefense - unit_count: - - 0 - - 2 - unit_classes: - - SHORAD - - name: S-300 Site SHORAD2 - optional: true - sub_task: PointDefense - unit_count: - - 0 - - 1 - unit_types: - - Tor 9A331 # Explicit TOR / SA-15 SHORAD PointDefense - - name: S-300 Site AAA - sub_task: AAA - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA diff --git a/resources/layouts/anti_air/SHORAD.yaml b/resources/layouts/anti_air/SHORAD.yaml deleted file mode 100644 index 205b3b8df..000000000 --- a/resources/layouts/anti_air/SHORAD.yaml +++ /dev/null @@ -1,19 +0,0 @@ -name: Short Range Anti Air Group -generic: true -tasks: - - SHORAD -groups: - - SHORAD: - - name: Launcher - unit_count: - - 2 - unit_classes: - - SHORAD - - name: Logistics - optional: true - unit_count: - - 0 - - 2 - unit_classes: - - Logistics -layout_file: resources/layouts/anti_air/2_Launcher.miz diff --git a/resources/layouts/anti_air/WW2_Ally_Flak_Site.miz b/resources/layouts/anti_air/WW2_Ally_Flak_Site.miz deleted file mode 100644 index aa768d08b..000000000 Binary files a/resources/layouts/anti_air/WW2_Ally_Flak_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/WW2_Ally_Flak_Site.yaml b/resources/layouts/anti_air/WW2_Ally_Flak_Site.yaml deleted file mode 100644 index 240135487..000000000 --- a/resources/layouts/anti_air/WW2_Ally_Flak_Site.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: WW2 Ally Flak Site -tasks: - - AAA -groups: - - Flak: - - name: WW2 Ally Flak Site 0 - unit_count: - - 4 - unit_types: - - QF_37_AA - - name: WW2 Ally Flak Site 1 - unit_count: - - 8 - unit_types: - - M1_37mm - - name: WW2 Ally Flak Site 2 - unit_count: - - 8 - unit_types: - - M45_Quadmount - - name: WW2 Ally Flak Site 3 - unit_count: - - 1 - unit_types: - - Willys_MB - - name: WW2 Ally Flak Site 4 - unit_count: - - 1 - unit_types: - - M30_CC - - name: WW2 Ally Flak Site 5 - unit_count: - - 1 - unit_types: - - M4_Tractor - - name: WW2 Ally Flak Site 6 - unit_count: - - 1 - unit_types: - - Bedford_MWD diff --git a/resources/layouts/anti_air/WW2_Flak_Site.miz b/resources/layouts/anti_air/WW2_Flak_Site.miz deleted file mode 100644 index 0e67dc42d..000000000 Binary files a/resources/layouts/anti_air/WW2_Flak_Site.miz and /dev/null differ diff --git a/resources/layouts/anti_air/WW2_Flak_Site.yaml b/resources/layouts/anti_air/WW2_Flak_Site.yaml deleted file mode 100644 index e9eb0c978..000000000 --- a/resources/layouts/anti_air/WW2_Flak_Site.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: WW2 Flak Site -tasks: - - AAA -groups: - - Flak: - - name: WW2 Flak Site 0 - unit_count: - - 6 - unit_types: - - flak18 - - name: WW2 Flak Site 1 - unit_count: - - 1 - unit_types: - - Blitz_36-6700A diff --git a/resources/layouts/anti_air/shorad.miz b/resources/layouts/anti_air/shorad.miz deleted file mode 100644 index 8c48b6b79..000000000 Binary files a/resources/layouts/anti_air/shorad.miz and /dev/null differ diff --git a/resources/layouts/buildings/allycamp1.yaml b/resources/layouts/buildings/allycamp1.yaml deleted file mode 100644 index 1e92ccf6f..000000000 --- a/resources/layouts/buildings/allycamp1.yaml +++ /dev/null @@ -1,84 +0,0 @@ -name: allycamp1 -generic: true -tasks: - - StrikeTarget - - AllyCamp -groups: - - AllyCamp: - - name: allycamp1 0 - statics: - - allycamp1 0-0 - - allycamp1 0-1 - - allycamp1 0-2 - - allycamp1 0-3 - unit_count: - - 4 - unit_types: - - FARP Tent - - name: allycamp1 1 - statics: - - allycamp1 1-0 - - allycamp1 1-1 - - allycamp1 1-2 - - allycamp1 1-3 - - allycamp1 1-4 - - allycamp1 1-5 - - allycamp1 1-6 - - allycamp1 1-7 - - allycamp1 1-8 - - allycamp1 1-9 - - allycamp1 1-10 - - allycamp1 1-11 - - allycamp1 1-12 - - allycamp1 1-13 - - allycamp1 1-14 - - allycamp1 1-15 - - allycamp1 1-16 - - allycamp1 1-17 - - allycamp1 1-18 - - allycamp1 1-19 - - allycamp1 1-20 - - allycamp1 1-21 - unit_count: - - 22 - unit_types: - - Haystack 4 - - name: allycamp1 2 - statics: - - allycamp1 2-0 - - allycamp1 2-1 - - allycamp1 2-2 - - allycamp1 2-3 - - allycamp1 2-4 - - allycamp1 2-5 - - allycamp1 2-6 - - allycamp1 2-7 - - allycamp1 2-8 - - allycamp1 2-9 - - allycamp1 2-10 - - allycamp1 2-11 - unit_count: - - 12 - unit_types: - - Haystack 3 - - name: allycamp1 3 - statics: - - allycamp1 3-0 - - allycamp1 3-1 - - allycamp1 3-2 - - allycamp1 3-3 - - allycamp1 3-4 - - allycamp1 3-5 - - allycamp1 3-6 - - allycamp1 3-7 - unit_count: - - 8 - unit_types: - - Concertina wire - - AllyCamp2: # Vehicle and static can not be mixed - - name: allycamp1 4 - unit_count: - - 4 - unit_types: - - house2arm -layout_file: resources/layouts/buildings/buildingsww2.miz diff --git a/resources/layouts/buildings/ammo1.yaml b/resources/layouts/buildings/ammo1.yaml deleted file mode 100644 index f588f6674..000000000 --- a/resources/layouts/buildings/ammo1.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: ammo1 -generic: true -tasks: - - Ammo -groups: - - Ammo: - - name: ammo1 0 - statics: - - ammo1 0-0 - unit_count: - - 1 - unit_types: - - .Ammunition depot - - name: ammo1 1 - statics: - - ammo1 1-0 - - ammo1 1-1 - unit_count: - - 2 - unit_types: - - Hangar B -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/buildings.miz b/resources/layouts/buildings/buildings.miz deleted file mode 100644 index 89c31adbd..000000000 Binary files a/resources/layouts/buildings/buildings.miz and /dev/null differ diff --git a/resources/layouts/buildings/buildingsww2.miz b/resources/layouts/buildings/buildingsww2.miz deleted file mode 100644 index c6d42c060..000000000 Binary files a/resources/layouts/buildings/buildingsww2.miz and /dev/null differ diff --git a/resources/layouts/buildings/command_center.yaml b/resources/layouts/buildings/command_center.yaml deleted file mode 100644 index 70a55975b..000000000 --- a/resources/layouts/buildings/command_center.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: command_center -generic: true -tasks: - - CommandCenter -groups: - - Command Center: - - name: CommandCenter 0 - statics: - - CommandCenter 0-0 - unit_count: - - 1 - unit_types: - - .Command Center -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/comms.yaml b/resources/layouts/buildings/comms.yaml deleted file mode 100644 index 88c19b49c..000000000 --- a/resources/layouts/buildings/comms.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: comms -generic: true -tasks: - - Comms -groups: - - Comms: - - name: comms1 0 - statics: - - comms1 0-0 - unit_count: - - 1 - unit_types: - - TV tower - - Comms tower M -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/derrick1.yaml b/resources/layouts/buildings/derrick1.yaml deleted file mode 100644 index 9b0342bb7..000000000 --- a/resources/layouts/buildings/derrick1.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: derrick1 -generic: true -tasks: - - StrikeTarget - - Derrick -groups: - - Derrick: - - name: derrick1 0 - statics: - - derrick1 0-0 - - derrick1 0-1 - unit_count: - - 2 - unit_types: - - Oil derrick - - name: derrick1 1 - statics: - - derrick1 1-0 - - derrick1 1-1 - unit_count: - - 2 - unit_types: - - Pump station - - name: derrick1 2 - statics: - - derrick1 2-0 - unit_count: - - 1 - unit_types: - - Subsidiary structure 2 -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/factory1.yaml b/resources/layouts/buildings/factory1.yaml deleted file mode 100644 index e69358e6c..000000000 --- a/resources/layouts/buildings/factory1.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: factory1 -generic: true -tasks: - - Factory -groups: - - Factory: - - name: factory1 0 - statics: - - factory1 0-0 - unit_count: - - 1 - unit_types: - - Tech combine - - name: factory1 1 - statics: - - factory1 1-0 - - factory1 1-1 - - factory1 1-2 - unit_count: - - 3 - unit_types: - - Tech hangar A -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/farp1.yaml b/resources/layouts/buildings/farp1.yaml deleted file mode 100644 index 60d5c0165..000000000 --- a/resources/layouts/buildings/farp1.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: farp1 -generic: true -tasks: - - StrikeTarget - - Farp -groups: - - Farp: - - name: farp1 0 - statics: - - farp1 0-0 - - farp1 0-1 - - farp1 0-2 - - farp1 0-3 - - farp1 0-4 - unit_count: - - 5 - unit_types: - - FARP Tent - - name: farp1 1 - statics: - - farp1 1-0 - unit_count: - - 1 - unit_types: - - FARP Ammo Dump Coating - - name: farp1 2 - statics: - - farp1 2-0 - unit_count: - - 1 - unit_types: - - FARP CP Blindage - - name: farp1 3 - statics: - - farp1 3-0 - - farp1 3-1 - unit_count: - - 2 - unit_types: - - FARP Fuel Depot -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/fob1.yaml b/resources/layouts/buildings/fob1.yaml deleted file mode 100644 index f9479e9aa..000000000 --- a/resources/layouts/buildings/fob1.yaml +++ /dev/null @@ -1,31 +0,0 @@ -name: fob1 -generic: true -tasks: - - FOB -groups: - - FOB: - - name: fob1 0 - statics: - - fob1 0-0 - unit_count: - - 1 - unit_types: - - .Command Center - - name: fob1 1 - statics: - - fob1 1-0 - - fob1 1-1 - - fob1 1-2 - unit_count: - - 3 - unit_types: - - Barracks 2 - - name: fob1 2 - statics: - - fob1 2-0 - - fob1 2-1 - unit_count: - - 2 - unit_types: - - Garage small B -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/fuel1.yaml b/resources/layouts/buildings/fuel1.yaml deleted file mode 100644 index c7a7a6566..000000000 --- a/resources/layouts/buildings/fuel1.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: fuel1 -generic: true -tasks: - - StrikeTarget - - Fuel -groups: - - Fuel: - - name: fuel1 0 - statics: - - fuel1 0-0 - - fuel1 0-1 - - fuel1 0-2 - - fuel1 0-3 - - fuel1 0-4 - - fuel1 0-5 - unit_count: - - 6 - unit_types: - - Tank - - name: fuel1 1 - statics: - - fuel1 1-0 - - fuel1 1-1 - unit_count: - - 2 - unit_types: - - Tank 3 -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/oil1.yaml b/resources/layouts/buildings/oil1.yaml deleted file mode 100644 index 3f19272db..000000000 --- a/resources/layouts/buildings/oil1.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: oil1 -generic: true -tasks: - - OffShoreStrikeTarget - - Oil -groups: - - Oil: - - name: oil1 0 - statics: - - oil1 0-0 - - oil1 0-1 - - oil1 0-2 - - oil1 0-3 - unit_count: - - 4 - unit_types: - - Oil platform -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/power1.yaml b/resources/layouts/buildings/power1.yaml deleted file mode 100644 index b0e65b40d..000000000 --- a/resources/layouts/buildings/power1.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: power1 -generic: true -tasks: - - Power -groups: - - Power: - - name: power1 0 - statics: - - power1 0-0 - unit_count: - - 1 - unit_types: - - Repair workshop - - name: power1 1 - statics: - - power1 1-0 - unit_count: - - 1 - unit_types: - - Workshop A - - name: power1 2 - statics: - - power1 2-0 - - power1 2-1 - unit_count: - - 2 - unit_types: - - Garage B - - name: power1 3 - statics: - - power1 3-0 - unit_count: - - 1 - unit_types: - - Farm B -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/village1.yaml b/resources/layouts/buildings/village1.yaml deleted file mode 100644 index 2ba7eeff3..000000000 --- a/resources/layouts/buildings/village1.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: village1 -generic: true -tasks: - - StrikeTarget - - Village -groups: - - Village: - - name: village1 0 - statics: - - village1 0-0 - - village1 0-1 - unit_count: - - 2 - unit_types: - - Small house 1A - - name: village1 1 - statics: - - village1 1-0 - - village1 1-1 - - village1 1-2 - - village1 1-3 - - village1 1-4 - - village1 1-5 - - village1 1-6 - - village1 1-7 - unit_count: - - 8 - unit_types: - - Small werehouse 1 - - name: village1 2 - statics: - - village1 2-0 - - village1 2-1 - - village1 2-2 - unit_count: - - 3 - unit_types: - - Small house 1B -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/ware1.yaml b/resources/layouts/buildings/ware1.yaml deleted file mode 100644 index a00889ee1..000000000 --- a/resources/layouts/buildings/ware1.yaml +++ /dev/null @@ -1,24 +0,0 @@ -name: ware1 -generic: true -tasks: - - StrikeTarget - - Ware -groups: - - Ware: - - name: ware1 0 - statics: - - ware1 0-0 - unit_count: - - 1 - unit_types: - - Warehouse - - name: ware1 1 - statics: - - ware1 1-0 - - ware1 1-1 - - ware1 1-2 - unit_count: - - 3 - unit_types: - - Hangar A -layout_file: resources/layouts/buildings/buildings.miz diff --git a/resources/layouts/buildings/ww2bunker1.yaml b/resources/layouts/buildings/ww2bunker1.yaml deleted file mode 100644 index 7c733a16f..000000000 --- a/resources/layouts/buildings/ww2bunker1.yaml +++ /dev/null @@ -1,34 +0,0 @@ -name: ww2bunker1 -generic: true -tasks: - - StrikeTarget - - WW2Bunker -groups: - - Bunker: - - name: ww2bunker1 0 - statics: - - ww2bunker1 0-0 - - ww2bunker1 0-1 - - ww2bunker1 0-2 - - ww2bunker1 0-3 - unit_count: - - 4 - unit_types: - - Siegfried Line - - name: ww2bunker1 1 - statics: - - ww2bunker1 1-0 - - ww2bunker1 1-1 - - ww2bunker1 1-2 - - ww2bunker1 1-3 - unit_count: - - 4 - unit_types: - - Fire Control Bunker - - Bunker2: # Vehicle and static can not be mixed - - name: ww2bunker1 2 - unit_count: - - 4 - unit_types: - - SK_C_28_naval_gun -layout_file: resources/layouts/buildings/buildingsww2.miz diff --git a/resources/layouts/buildings/ww2bunker2.yaml b/resources/layouts/buildings/ww2bunker2.yaml deleted file mode 100644 index 336c190ca..000000000 --- a/resources/layouts/buildings/ww2bunker2.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: ww2bunker2 -generic: true -tasks: - - StrikeTarget - - WW2Bunker -groups: - - Bunker: - - name: ww2bunker2 0 - statics: - - ww2bunker2 0-0 - unit_count: - - 1 - unit_types: - - Fire Control Bunker - - name: ww2bunker2 1 - statics: - - ww2bunker2 1-0 - - ww2bunker2 1-1 - unit_count: - - 2 - unit_types: - - Siegfried Line - - name: ww2bunker2 2 - statics: - - ww2bunker2 2-0 - - ww2bunker2 2-1 - - ww2bunker2 2-2 - - ww2bunker2 2-3 - - ww2bunker2 2-4 - - ww2bunker2 2-5 - - ww2bunker2 2-6 - - ww2bunker2 2-7 - unit_count: - - 8 - unit_types: - - Concertina wire - - name: ww2bunker2 3 - statics: - - ww2bunker2 3-0 - unit_count: - - 1 - unit_types: - - Belgian gate - - name: ww2bunker2 4 - statics: - - ww2bunker2 4-0 - - ww2bunker2 4-1 - - ww2bunker2 4-2 - - ww2bunker2 4-3 - - ww2bunker2 4-4 - - ww2bunker2 4-5 - - ww2bunker2 4-6 - unit_count: - - 7 - unit_types: - - Czech hedgehogs 1 -layout_file: resources/layouts/buildings/buildingsww2.miz diff --git a/resources/layouts/defenses/Silkworm.miz b/resources/layouts/defenses/Silkworm.miz deleted file mode 100644 index 4a5cbd722..000000000 Binary files a/resources/layouts/defenses/Silkworm.miz and /dev/null differ diff --git a/resources/layouts/defenses/Silkworm.yaml b/resources/layouts/defenses/Silkworm.yaml deleted file mode 100644 index 381658110..000000000 --- a/resources/layouts/defenses/Silkworm.yaml +++ /dev/null @@ -1,36 +0,0 @@ -name: Silkworm -tasks: - - Coastal -groups: - - Silkworm: - - name: SilkwormGenerator 0 - unit_count: - - 1 - unit_classes: - - SearchRadar - - name: SilkwormGenerator 1 - unit_count: - - 5 - unit_classes: - - AntiShipMissile - - name: SilkwormGenerator 2 - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - Logistics - - name: SilkwormGenerator 3 - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA - - name: SilkwormGenerator 4 - optional: true - unit_count: - - 0 - - 1 - unit_classes: - - SHORAD \ No newline at end of file diff --git a/resources/layouts/defenses/missile.miz b/resources/layouts/defenses/missile.miz deleted file mode 100644 index 875842eb7..000000000 Binary files a/resources/layouts/defenses/missile.miz and /dev/null differ diff --git a/resources/layouts/defenses/missile.yaml b/resources/layouts/defenses/missile.yaml deleted file mode 100644 index 39349cb73..000000000 --- a/resources/layouts/defenses/missile.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: Missile -generic: true -tasks: - - Missile -groups: - - Missile: - - name: ScudGenerator 0 - unit_count: - - 3 - unit_classes: - - Missile - - name: ScudGenerator 1 - unit_count: - - 1 - unit_classes: - - Logistics - - name: ScudGenerator 2 - optional: true - unit_count: - - 1 - unit_classes: - - AAA - - name: ScudGenerator 3 - optional: true - unit_count: - - 0 - - 1 - unit_classes: - - SHORAD \ No newline at end of file diff --git a/resources/layouts/ground_forces/Armor_Group.yaml b/resources/layouts/ground_forces/Armor_Group.yaml deleted file mode 100644 index acee4ca5f..000000000 --- a/resources/layouts/ground_forces/Armor_Group.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Armor Group -generic: true -tasks: - - BaseDefense - - FrontLine -groups: - - Armor Group: - - name: Armor Group 0 - unit_count: - - 2 - - 6 - unit_classes: - - APC - - ATGM - - IFV - - Tank -layout_file: resources/layouts/ground_forces/ground_forces.miz diff --git a/resources/layouts/ground_forces/Armor_Group_with_Anti-Air.yaml b/resources/layouts/ground_forces/Armor_Group_with_Anti-Air.yaml deleted file mode 100644 index 50d9be530..000000000 --- a/resources/layouts/ground_forces/Armor_Group_with_Anti-Air.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: Armor Group with Anti-Air -generic: true -tasks: - - BaseDefense - - FrontLine -groups: - - Armor Group: - - name: Armor Group with Anti-Air 0 - unit_count: - - 2 - - 6 - unit_classes: - - APC - - ATGM - - IFV - - Tank - - name: Armor Group with Anti-Air 1 - optional: true - unit_count: - - 1 - - 2 - unit_classes: - - AAA - - SHORAD - - Manpad -layout_file: resources/layouts/ground_forces/ground_forces.miz diff --git a/resources/layouts/ground_forces/ground_forces.miz b/resources/layouts/ground_forces/ground_forces.miz deleted file mode 100644 index 45457eb73..000000000 Binary files a/resources/layouts/ground_forces/ground_forces.miz and /dev/null differ diff --git a/resources/layouts/naval/Carrier_Group.miz b/resources/layouts/naval/Carrier_Group.miz deleted file mode 100644 index 85a78ca53..000000000 Binary files a/resources/layouts/naval/Carrier_Group.miz and /dev/null differ diff --git a/resources/layouts/naval/Carrier_Group.yaml b/resources/layouts/naval/Carrier_Group.yaml deleted file mode 100644 index d4a176007..000000000 --- a/resources/layouts/naval/Carrier_Group.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Carrier Group -generic: true -tasks: - - AircraftCarrier -groups: - - Carrier: - - name: Carrier Group 0 - unit_count: - - 1 - unit_classes: - - AircraftCarrier - - Escort: - - name: Carrier Group 1 - unit_count: - - 4 - unit_classes: - - Destroyer diff --git a/resources/layouts/naval/Carrier_Strike_Group_8.miz b/resources/layouts/naval/Carrier_Strike_Group_8.miz deleted file mode 100644 index 78983415f..000000000 Binary files a/resources/layouts/naval/Carrier_Strike_Group_8.miz and /dev/null differ diff --git a/resources/layouts/naval/Carrier_Strike_Group_8.yaml b/resources/layouts/naval/Carrier_Strike_Group_8.yaml deleted file mode 100644 index ae37b1262..000000000 --- a/resources/layouts/naval/Carrier_Strike_Group_8.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Carrier Strike Group 8 -generic: true -tasks: - - AircraftCarrier -groups: - - Carrier: - - name: Carrier Strike Group 8 0 - unit_count: - - 1 - unit_types: - - Stennis - - Escort: - - name: Carrier Strike Group 8 1 - unit_count: - - 4 - unit_types: - - USS_Arleigh_Burke_IIa - - name: Carrier Strike Group 8 2 - unit_count: - - 1 - unit_types: - - TICONDEROG diff --git a/resources/layouts/naval/LHA_Group.miz b/resources/layouts/naval/LHA_Group.miz deleted file mode 100644 index 806ed908d..000000000 Binary files a/resources/layouts/naval/LHA_Group.miz and /dev/null differ diff --git a/resources/layouts/naval/LHA_Group.yaml b/resources/layouts/naval/LHA_Group.yaml deleted file mode 100644 index 64844d575..000000000 --- a/resources/layouts/naval/LHA_Group.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: LHA Group -generic: true -tasks: - - HelicopterCarrier -groups: - - LHA: - - name: LHA Group 0 - unit_count: - - 1 - unit_classes: - - HelicopterCarrier - - Escort: - - name: LHA Group 1 - unit_count: - - 2 - unit_classes: - - Destroyer diff --git a/resources/layouts/naval/Naval-Group.miz b/resources/layouts/naval/Naval-Group.miz deleted file mode 100644 index 9dcc971a0..000000000 Binary files a/resources/layouts/naval/Naval-Group.miz and /dev/null differ diff --git a/resources/layouts/naval/Naval-Group.yaml b/resources/layouts/naval/Naval-Group.yaml deleted file mode 100644 index dafd669d4..000000000 --- a/resources/layouts/naval/Naval-Group.yaml +++ /dev/null @@ -1,22 +0,0 @@ -name: Naval Group -tasks: - - Navy -groups: - - Naval Group: - - name: Naval Group 0 - unit_count: - - 2 - unit_classes: - - Frigate - - name: Naval Group 1 - unit_count: - - 2 - unit_classes: - - Destroyer - - name: Naval Group 2 - optional: true - unit_count: - - 0 - - 1 - unit_classes: - - Cruiser diff --git a/resources/layouts/naval/Naval-Two-Ship.miz b/resources/layouts/naval/Naval-Two-Ship.miz deleted file mode 100644 index 69b6035a5..000000000 Binary files a/resources/layouts/naval/Naval-Two-Ship.miz and /dev/null differ diff --git a/resources/layouts/naval/Naval-Two-Ship.yaml b/resources/layouts/naval/Naval-Two-Ship.yaml deleted file mode 100644 index 7538eeef2..000000000 --- a/resources/layouts/naval/Naval-Two-Ship.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: Naval Two Ship -generic: true -tasks: - - Navy -groups: - - Naval Two Ship: - - name: Naval Two Ship - unit_count: - - 2 - unit_classes: - - Frigate - - Destroyer - - Cruiser - - Boat - - Submarine - - LandingShip diff --git a/resources/layouts/naval/WW2-LST.miz b/resources/layouts/naval/WW2-LST.miz deleted file mode 100644 index 8bd80659f..000000000 Binary files a/resources/layouts/naval/WW2-LST.miz and /dev/null differ diff --git a/resources/layouts/naval/WW2-LST.yaml b/resources/layouts/naval/WW2-LST.yaml deleted file mode 100644 index d9dad673a..000000000 --- a/resources/layouts/naval/WW2-LST.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: WW2 LST Group -role: Naval -tasks: - - Navy -groups: - - LST: - - name: WW2 LST Group 0 - unit_count: - - 1 - unit_types: - - USS_Samuel_Chase - - name: WW2 LST Group 1 - unit_count: - - 3 - unit_types: - - LST_Mk2 diff --git a/resources/layouts/original_generator_layouts.miz b/resources/layouts/original_generator_layouts.miz deleted file mode 100644 index 914ea7b04..000000000 Binary files a/resources/layouts/original_generator_layouts.miz and /dev/null differ diff --git a/resources/marianasislands.gif b/resources/marianasislands.gif deleted file mode 100644 index f9217dd47..000000000 Binary files a/resources/marianasislands.gif and /dev/null differ diff --git a/resources/nevada.gif b/resources/nevada.gif deleted file mode 100644 index e2cf11368..000000000 Binary files a/resources/nevada.gif and /dev/null differ diff --git a/resources/nevada.p b/resources/nevada.p deleted file mode 100644 index 41c1a6139..000000000 Binary files a/resources/nevada.p and /dev/null differ diff --git a/resources/normandy.gif b/resources/normandy.gif deleted file mode 100644 index 39b9e6a04..000000000 Binary files a/resources/normandy.gif and /dev/null differ diff --git a/resources/payloads/_directory_for_payloads b/resources/payloads/_directory_for_payloads deleted file mode 100644 index e69de29bb..000000000 diff --git a/resources/persiangulf.gif b/resources/persiangulf.gif deleted file mode 100644 index 0bf948078..000000000 Binary files a/resources/persiangulf.gif and /dev/null differ diff --git a/resources/plugins/_doc/0.png b/resources/plugins/_doc/0.png deleted file mode 100644 index 3320b9088..000000000 Binary files a/resources/plugins/_doc/0.png and /dev/null differ diff --git a/resources/plugins/_doc/1.png b/resources/plugins/_doc/1.png deleted file mode 100644 index 069c45db3..000000000 Binary files a/resources/plugins/_doc/1.png and /dev/null differ diff --git a/resources/plugins/_doc/2.png b/resources/plugins/_doc/2.png deleted file mode 100644 index 97952fdea..000000000 Binary files a/resources/plugins/_doc/2.png and /dev/null differ diff --git a/resources/plugins/_doc/plugins_readme.md b/resources/plugins/_doc/plugins_readme.md deleted file mode 100644 index 8af9802b9..000000000 --- a/resources/plugins/_doc/plugins_readme.md +++ /dev/null @@ -1,68 +0,0 @@ -# LUA Plugin system - -This plugin system was made for injecting LUA scripts in dcs-liberation missions. - -The resources for the plugins are stored in the `resources/plugins` folder ; each plugin has its own folder. - -## How does the system work ? - -The application first reads the `resources/plugins/plugins.json` file to get a list of plugins to load, in order. -Each entry in this list should correspond to a subfolder of the `resources/plugins` directory, where a `plugin.json` file exists. -This file is the description of the plugin. - -### plugin.json - -The *base* and *jtacautolase* plugins both are included in the standard dcs-liberation distribution. -You can check their respective `plugin.json` files to understand how they work. -Here's a quick rundown of the file's components : - -- `skipUI` : if *true*, this plugin will not appear in the plugins selection user interface. Useful to force a plugin ON or OFF (see the *base* plugin) -- `nameInUI` : the title of the plugin as it will appear in the plugins selection user interface. -- `defaultValue` : the selection value of the plugin, when first installed ; if true, plugin is selected. -- `specificOptions` : a list of specific plugin options - - `nameInUI` : the title of the option as it will appear in the plugins specific options user interface. - - `mnemonic` : the short, technical name of the option. It's the name of the LUA variable passed to the configuration script, and the name of the option in the application's settings - - `defaultValue` : the selection value of the option, when first installed ; if true, option is selected. -- `scriptsWorkOrders` : a list of work orders that can be used to load or disable loading a specific LUA script - - `file` : the name of the LUA file in the plugin folder. - - `mnemonic` : the technical name of the LUA component. The filename may be more precise than needed (e.g. include a version number) ; this is used to load each file only once, and also to disable loading a file - - `disable` : if true, the script will be disabled instead of loaded -- `configurationWorkOrders` : a list of work orders that can be used to load a configuration LUA script (same description as above) - -## Standard plugins - -### The *base* plugin - -The *base* plugin contains the scripts that are going to be injected in every dcs-liberation missions. -It is mandatory. - -### The *JTACAutolase* plugin - -This plugin replaces the vanilla JTAC functionality in dcs-liberation. - -### Known third-party plugins - -Plugins not included with Liberation can be installed by adding them to the -`resources/plugins` directory and listing them in -`resources/plugins/plugins.json`. Below is a list of other plugins that can be -installed: - -* [VEAF](https://github.com/VEAF/dcs-liberation-veaf-framework) - -## Custom plugins - -The easiest way to create a custom plugin is to copy an existing plugin, and modify the files. - -## New settings pages - -![New settings pages](0.png "New settings pages") - -Custom plugins can be enabled or disabled in the new *LUA Plugins* settings page. - -![LUA Plugins settings page](1.png "LUA Plugins settings page") - -For plugins which expose specific options (such as "use smoke" for the *JTACAutoLase* plugin), the *LUA Plugins Options* settings page lists these options. - -![LUA Plugins Options settings page](2.png "LUA Plugins settings page") - - diff --git a/resources/plugins/base/dcs_liberation.lua b/resources/plugins/base/dcs_liberation.lua deleted file mode 100644 index f94771c30..000000000 --- a/resources/plugins/base/dcs_liberation.lua +++ /dev/null @@ -1,208 +0,0 @@ --- the state.json file will be updated according to this schedule, and also on each destruction or capture event -local WRITESTATE_SCHEDULE_IN_SECONDS = 60 - -logger = mist.Logger:new("DCSLiberation", "info") -logger:info("Check that json.lua is loaded : json = "..tostring(json)) - -crash_events = {} -- killed aircraft will be added via S_EVENT_CRASH event -dead_events = {} -- killed units will be added via S_EVENT_DEAD event -unit_lost_events = {} -- killed units will be added via S_EVENT_UNIT_LOST -kill_events = {} -- killed units will be added via S_EVENT_KILL -base_capture_events = {} -destroyed_objects_positions = {} -- will be added via S_EVENT_DEAD event -killed_ground_units = {} -- keep track of static ground object deaths -unit_hit_point_updates = {} -- stores updates to unit hit points, triggered by S_EVENT_HIT -mission_ended = false - -local function ends_with(str, ending) - return ending == "" or str:sub(-#ending) == ending -end - -local function messageAll(message) - local msg = {} - msg.text = message - msg.displayTime = 25 - msg.msgFor = {coa = {'all'}} - mist.message.add(msg) -end - -function write_state() - local _debriefing_file_location = debriefing_file_location - if not debriefing_file_location then - _debriefing_file_location = "[nil]" - end - - local fp = io.open(_debriefing_file_location, 'w') - local game_state = { - ["crash_events"] = crash_events, - ["dead_events"] = dead_events, - ["base_capture_events"] = base_capture_events, - ["unit_lost_events"] = unit_lost_events, - ["kill_events"] = kill_events, - ["mission_ended"] = mission_ended, - ["destroyed_objects_positions"] = destroyed_objects_positions, - ["killed_ground_units"] = killed_ground_units, - ["unit_hit_point_updates"] = unit_hit_point_updates, - } - if not json then - local message = string.format("Unable to save DCS Liberation state to %s, JSON library is not loaded !", _debriefing_file_location) - logger:error(message) - messageAll(message) - end - fp:write(json:encode(game_state)) - fp:close() -end - -local function canWrite(name) - local f = io.open(name, "w") - if f then - f:close() - return true - end - return false -end - -local function testDebriefingFilePath(folderPath, folderName, useCurrentStamping) - if folderPath then - local filePath = nil - if not ends_with(folderPath, "\\") then - folderPath = folderPath .. "\\" - end - if useCurrentStamping then - filePath = string.format("%sstate-%s.json",folderPath, tostring(os.time())) - else - filePath = string.format("%sstate.json",folderPath) - end - local isOk = canWrite(filePath) - if isOk then - logger:info(string.format("The state.json file will be created in %s : (%s)",folderName, filePath)) - return filePath - end - end - return nil -end - -local function discoverDebriefingFilePath() - -- establish a search pattern into the following modes - -- 1. Environment variable LIBERATION_EXPORT_DIR, to support dedicated server hosting - -- 2. Embedded DCS Liberation dcsLiberation.installPath (set by the app to its install path), to support locally hosted single player - -- 3. System temporary folder, as set in the TEMP environment variable - -- 4. Working directory. - - local useCurrentStamping = nil - if os then - useCurrentStamping = os.getenv("LIBERATION_EXPORT_STAMPED_STATE") - end - - local installPath = nil - if dcsLiberation then - installPath = dcsLiberation.installPath - end - - if os then - local result = nil - -- try using the LIBERATION_EXPORT_DIR environment variable - result = testDebriefingFilePath(os.getenv("LIBERATION_EXPORT_DIR"), "LIBERATION_EXPORT_DIR", useCurrentStamping) - if result then - return result - end - -- no joy ? maybe there is a valid path in the mission ? - result = testDebriefingFilePath(installPath, "the DCS Liberation install folder", useCurrentStamping) - if result then - return result - end - -- there's always the possibility of using the system temporary folder - result = testDebriefingFilePath(os.getenv("TEMP"), "TEMP", useCurrentStamping) - if result then - return result - end - end - - -- nothing worked, let's try the last resort folder : current directory. - if lfs then - return testDebriefingFilePath(lfs.writedir().."Missions\\", "the working directory", useCurrentStamping) - end - - return nil -end - -debriefing_file_location = discoverDebriefingFilePath() - -write_state_error_handling = function() - local _debriefing_file_location = debriefing_file_location - if not debriefing_file_location then - _debriefing_file_location = "[nil]" - logger:error("Unable to find where to write DCS Liberation state") - end - - if pcall(write_state) then - else - messageAll("Unable to write DCS Liberation state to ".._debriefing_file_location.. - "\nYou can abort the mission in DCS Liberation.\n".. - "\n\nPlease fix your setup in DCS Liberation, make sure you are pointing to the right installation directory from the File/Preferences menu. Then after fixing the path restart DCS Liberation, and then restart DCS.".. - "\n\nYou can also try to fix the issue manually by replacing the file /Scripts/MissionScripting.lua by the one provided there : /resources/scripts/MissionScripting.lua. And then restart DCS. (This will also have to be done again after each DCS update)".. - "\n\nIt's not worth playing, the state of the mission will not be recorded.") - end - - -- reschedule - mist.scheduleFunction(write_state_error_handling, {}, timer.getTime() + WRITESTATE_SCHEDULE_IN_SECONDS) -end - -function update_hit_points(event) - local update = {} - update.name = event.target:getName() - update.hit_points = event.target:getLife() - unit_hit_point_updates[#unit_hit_point_updates + 1] = update - write_state() -end - -activeWeapons = {} -local function onEvent(event) - if event.id == world.event.S_EVENT_CRASH and event.initiator then - crash_events[#crash_events + 1] = event.initiator.getName(event.initiator) - write_state() - end - - if event.id == world.event.S_EVENT_UNIT_LOST and event.initiator then - unit_lost_events[#unit_lost_events + 1] = event.initiator.getName(event.initiator) - write_state() - end - - if event.id == world.event.S_EVENT_KILL and event.target then - kill_events[#kill_events + 1] = event.target.getName(event.target) - write_state() - end - - if event.id == world.event.S_EVENT_DEAD and event.initiator then - dead_events[#dead_events + 1] = event.initiator.getName(event.initiator) - local position = event.initiator.getPosition(event.initiator) - local destruction = {} - destruction.x = position.p.x - destruction.y = position.p.y - destruction.z = position.p.z - destruction.type = event.initiator:getTypeName() - destruction.orientation = mist.getHeading(event.initiator) * 57.3 - destroyed_objects_positions[#destroyed_objects_positions + 1] = destruction - write_state() - end - - if event.id == world.event.S_EVENT_HIT then - target_category = event.target:getCategory() - if target_category == Object.Category.UNIT then - -- check on the health of the target 1 second after as the life value is sometimes not updated - -- at the time of the event - timer.scheduleFunction(update_hit_points, event, timer.getTime() + 1) - end - end - - if event.id == world.event.S_EVENT_MISSION_END then - mission_ended = true - write_state() - end - -end - -mist.addEventHandler(onEvent) - --- create the state.json file and start the scheduling -write_state_error_handling() \ No newline at end of file diff --git a/resources/plugins/base/json.lua b/resources/plugins/base/json.lua deleted file mode 100644 index 632c68400..000000000 --- a/resources/plugins/base/json.lua +++ /dev/null @@ -1,1054 +0,0 @@ --- -*- coding: utf-8 -*- --- --- Simple JSON encoding and decoding in pure Lua. --- --- Copyright 2010-2014 Jeffrey Friedl --- http://regex.info/blog/ --- --- Latest version: http://regex.info/blog/lua/json --- --- This code is released under a Creative Commons CC-BY "Attribution" License: --- http://creativecommons.org/licenses/by/3.0/deed.en_US --- --- It can be used for any purpose so long as the copyright notice above, --- the web-page links above, and the 'AUTHOR_NOTE' string below are --- maintained. Enjoy. --- -local VERSION = 20141223.14 -- version history at end of file -local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20141223.14 ]-" - --- --- The 'AUTHOR_NOTE' variable exists so that information about the source --- of the package is maintained even in compiled versions. It's also --- included in OBJDEF below mostly to quiet warnings about unused variables. --- -local OBJDEF = { - VERSION = VERSION, - AUTHOR_NOTE = AUTHOR_NOTE, -} - - --- --- Simple JSON encoding and decoding in pure Lua. --- http://www.json.org/ --- --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local lua_value = JSON:decode(raw_json_text) --- --- local raw_json_text = JSON:encode(lua_table_or_value) --- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability --- --- --- --- DECODING (from a JSON string to a Lua table) --- --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local lua_value = JSON:decode(raw_json_text) --- --- If the JSON text is for an object or an array, e.g. --- { "what": "books", "count": 3 } --- or --- [ "Larry", "Curly", "Moe" ] --- --- the result is a Lua table, e.g. --- { what = "books", count = 3 } --- or --- { "Larry", "Curly", "Moe" } --- --- --- The encode and decode routines accept an optional second argument, --- "etc", which is not used during encoding or decoding, but upon error --- is passed along to error handlers. It can be of any type (including nil). --- --- --- --- ERROR HANDLING --- --- With most errors during decoding, this code calls --- --- JSON:onDecodeError(message, text, location, etc) --- --- with a message about the error, and if known, the JSON text being --- parsed and the byte count where the problem was discovered. You can --- replace the default JSON:onDecodeError() with your own function. --- --- The default onDecodeError() merely augments the message with data --- about the text and the location if known (and if a second 'etc' --- argument had been provided to decode(), its value is tacked onto the --- message as well), and then calls JSON.assert(), which itself defaults --- to Lua's built-in assert(), and can also be overridden. --- --- For example, in an Adobe Lightroom plugin, you might use something like --- --- function JSON:onDecodeError(message, text, location, etc) --- LrErrors.throwUserError("Internal Error: invalid JSON data") --- end --- --- or even just --- --- function JSON.assert(message) --- LrErrors.throwUserError("Internal Error: " .. message) --- end --- --- If JSON:decode() is passed a nil, this is called instead: --- --- JSON:onDecodeOfNilError(message, nil, nil, etc) --- --- and if JSON:decode() is passed HTML instead of JSON, this is called: --- --- JSON:onDecodeOfHTMLError(message, text, nil, etc) --- --- The use of the fourth 'etc' argument allows stronger coordination --- between decoding and error reporting, especially when you provide your --- own error-handling routines. Continuing with the the Adobe Lightroom --- plugin example: --- --- function JSON:onDecodeError(message, text, location, etc) --- local note = "Internal Error: invalid JSON data" --- if type(etc) = 'table' and etc.photo then --- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName') --- end --- LrErrors.throwUserError(note) --- end --- --- : --- : --- --- for i, photo in ipairs(photosToProcess) do --- : --- : --- local data = JSON:decode(someJsonText, { photo = photo }) --- : --- : --- end --- --- --- --- --- --- DECODING AND STRICT TYPES --- --- Because both JSON objects and JSON arrays are converted to Lua tables, --- it's not normally possible to tell which original JSON type a --- particular Lua table was derived from, or guarantee decode-encode --- round-trip equivalency. --- --- However, if you enable strictTypes, e.g. --- --- JSON = assert(loadfile "JSON.lua")() --load the routines --- JSON.strictTypes = true --- --- then the Lua table resulting from the decoding of a JSON object or --- JSON array is marked via Lua metatable, so that when re-encoded with --- JSON:encode() it ends up as the appropriate JSON type. --- --- (This is not the default because other routines may not work well with --- tables that have a metatable set, for example, Lightroom API calls.) --- --- --- ENCODING (from a lua table to a JSON string) --- --- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines --- --- local raw_json_text = JSON:encode(lua_table_or_value) --- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability --- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false }) --- --- On error during encoding, this code calls: --- --- JSON:onEncodeError(message, etc) --- --- which you can override in your local JSON object. --- --- The 'etc' in the error call is the second argument to encode() --- and encode_pretty(), or nil if it wasn't provided. --- --- --- PRETTY-PRINTING --- --- An optional third argument, a table of options, allows a bit of --- configuration about how the encoding takes place: --- --- pretty = JSON:encode(val, etc, { --- pretty = true, -- if false, no other options matter --- indent = " ", -- this provides for a three-space indent per nesting level --- align_keys = false, -- see below --- }) --- --- encode() and encode_pretty() are identical except that encode_pretty() --- provides a default options table if none given in the call: --- --- { pretty = true, align_keys = false, indent = " " } --- --- For example, if --- --- JSON:encode(data) --- --- produces: --- --- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11} --- --- then --- --- JSON:encode_pretty(data) --- --- produces: --- --- { --- "city": "Kyoto", --- "climate": { --- "avg_temp": 16, --- "humidity": "high", --- "snowfall": "minimal" --- }, --- "country": "Japan", --- "wards": 11 --- } --- --- The following three lines return identical results: --- JSON:encode_pretty(data) --- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " }) --- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " }) --- --- An example of setting your own indent string: --- --- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " }) --- --- produces: --- --- { --- | "city": "Kyoto", --- | "climate": { --- | | "avg_temp": 16, --- | | "humidity": "high", --- | | "snowfall": "minimal" --- | }, --- | "country": "Japan", --- | "wards": 11 --- } --- --- An example of setting align_keys to true: --- --- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true }) --- --- produces: --- --- { --- "city": "Kyoto", --- "climate": { --- "avg_temp": 16, --- "humidity": "high", --- "snowfall": "minimal" --- }, --- "country": "Japan", --- "wards": 11 --- } --- --- which I must admit is kinda ugly, sorry. This was the default for --- encode_pretty() prior to version 20141223.14. --- --- --- AMBIGUOUS SITUATIONS DURING THE ENCODING --- --- During the encode, if a Lua table being encoded contains both string --- and numeric keys, it fits neither JSON's idea of an object, nor its --- idea of an array. To get around this, when any string key exists (or --- when non-positive numeric keys exist), numeric keys are converted to --- strings. --- --- For example, --- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) --- produces the JSON object --- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} --- --- To prohibit this conversion and instead make it an error condition, set --- JSON.noKeyConversion = true --- - - - - --- --- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT --- --- assert --- onDecodeError --- onDecodeOfNilError --- onDecodeOfHTMLError --- onEncodeError --- --- If you want to create a separate Lua JSON object with its own error handlers, --- you can reload JSON.lua or use the :new() method. --- ---------------------------------------------------------------------------- - -local default_pretty_indent = " " -local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent } - -local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray -local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject - - -function OBJDEF:newArray(tbl) - return setmetatable(tbl or {}, isArray) -end - -function OBJDEF:newObject(tbl) - return setmetatable(tbl or {}, isObject) -end - -local function unicode_codepoint_as_utf8(codepoint) - -- - -- codepoint is a number - -- - if codepoint <= 127 then - return string.char(codepoint) - - elseif codepoint <= 2047 then - -- - -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8 - -- - local highpart = math.floor(codepoint / 0x40) - local lowpart = codepoint - (0x40 * highpart) - return string.char(0xC0 + highpart, - 0x80 + lowpart) - - elseif codepoint <= 65535 then - -- - -- 1110yyyy 10yyyyxx 10xxxxxx - -- - local highpart = math.floor(codepoint / 0x1000) - local remainder = codepoint - 0x1000 * highpart - local midpart = math.floor(remainder / 0x40) - local lowpart = remainder - 0x40 * midpart - - highpart = 0xE0 + highpart - midpart = 0x80 + midpart - lowpart = 0x80 + lowpart - - -- - -- Check for an invalid character (thanks Andy R. at Adobe). - -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070 - -- - if ( highpart == 0xE0 and midpart < 0xA0 ) or - ( highpart == 0xED and midpart > 0x9F ) or - ( highpart == 0xF0 and midpart < 0x90 ) or - ( highpart == 0xF4 and midpart > 0x8F ) - then - return "?" - else - return string.char(highpart, - midpart, - lowpart) - end - - else - -- - -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx - -- - local highpart = math.floor(codepoint / 0x40000) - local remainder = codepoint - 0x40000 * highpart - local midA = math.floor(remainder / 0x1000) - remainder = remainder - 0x1000 * midA - local midB = math.floor(remainder / 0x40) - local lowpart = remainder - 0x40 * midB - - return string.char(0xF0 + highpart, - 0x80 + midA, - 0x80 + midB, - 0x80 + lowpart) - end -end - -function OBJDEF:onDecodeError(message, text, location, etc) - if text then - if location then - message = string.format("%s at char %d of: %s", message, location, text) - else - message = string.format("%s: %s", message, text) - end - end - - if etc ~= nil then - message = message .. " (" .. OBJDEF:encode(etc) .. ")" - end - - if self.assert then - self.assert(false, message) - else - assert(false, message) - end -end - -OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError -OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError - -function OBJDEF:onEncodeError(message, etc) - if etc ~= nil then - message = message .. " (" .. OBJDEF:encode(etc) .. ")" - end - - if self.assert then - self.assert(false, message) - else - assert(false, message) - end -end - -local function grok_number(self, text, start, etc) - -- - -- Grab the integer part - -- - local integer_part = text:match('^-?[1-9]%d*', start) - or text:match("^-?0", start) - - if not integer_part then - self:onDecodeError("expected number", text, start, etc) - end - - local i = start + integer_part:len() - - -- - -- Grab an optional decimal part - -- - local decimal_part = text:match('^%.%d+', i) or "" - - i = i + decimal_part:len() - - -- - -- Grab an optional exponential part - -- - local exponent_part = text:match('^[eE][-+]?%d+', i) or "" - - i = i + exponent_part:len() - - local full_number_text = integer_part .. decimal_part .. exponent_part - local as_number = tonumber(full_number_text) - - if not as_number then - self:onDecodeError("bad number", text, start, etc) - end - - return as_number, i -end - - -local function grok_string(self, text, start, etc) - - if text:sub(start,start) ~= '"' then - self:onDecodeError("expected string's opening quote", text, start, etc) - end - - local i = start + 1 -- +1 to bypass the initial quote - local text_len = text:len() - local VALUE = "" - while i <= text_len do - local c = text:sub(i,i) - if c == '"' then - return VALUE, i + 1 - end - if c ~= '\\' then - VALUE = VALUE .. c - i = i + 1 - elseif text:match('^\\b', i) then - VALUE = VALUE .. "\b" - i = i + 2 - elseif text:match('^\\f', i) then - VALUE = VALUE .. "\f" - i = i + 2 - elseif text:match('^\\n', i) then - VALUE = VALUE .. "\n" - i = i + 2 - elseif text:match('^\\r', i) then - VALUE = VALUE .. "\r" - i = i + 2 - elseif text:match('^\\t', i) then - VALUE = VALUE .. "\t" - i = i + 2 - else - local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) - if hex then - i = i + 6 -- bypass what we just read - - -- We have a Unicode codepoint. It could be standalone, or if in the proper range and - -- followed by another in a specific range, it'll be a two-code surrogate pair. - local codepoint = tonumber(hex, 16) - if codepoint >= 0xD800 and codepoint <= 0xDBFF then - -- it's a hi surrogate... see whether we have a following low - local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) - if lo_surrogate then - i = i + 6 -- bypass the low surrogate we just read - codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16) - else - -- not a proper low, so we'll just leave the first codepoint as is and spit it out. - end - end - VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint) - - else - - -- just pass through what's escaped - VALUE = VALUE .. text:match('^\\(.)', i) - i = i + 2 - end - end - end - - self:onDecodeError("unclosed string", text, start, etc) -end - -local function skip_whitespace(text, start) - - local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2 - if match_end then - return match_end + 1 - else - return start - end -end - -local grok_one -- assigned later - -local function grok_object(self, text, start, etc) - if text:sub(start,start) ~= '{' then - self:onDecodeError("expected '{'", text, start, etc) - end - - local i = skip_whitespace(text, start + 1) -- +1 to skip the '{' - - local VALUE = self.strictTypes and self:newObject { } or { } - - if text:sub(i,i) == '}' then - return VALUE, i + 1 - end - local text_len = text:len() - while i <= text_len do - local key, new_i = grok_string(self, text, i, etc) - - i = skip_whitespace(text, new_i) - - if text:sub(i, i) ~= ':' then - self:onDecodeError("expected colon", text, i, etc) - end - - i = skip_whitespace(text, i + 1) - - local new_val, new_i = grok_one(self, text, i) - - VALUE[key] = new_val - - -- - -- Expect now either '}' to end things, or a ',' to allow us to continue. - -- - i = skip_whitespace(text, new_i) - - local c = text:sub(i,i) - - if c == '}' then - return VALUE, i + 1 - end - - if text:sub(i, i) ~= ',' then - self:onDecodeError("expected comma or '}'", text, i, etc) - end - - i = skip_whitespace(text, i + 1) - end - - self:onDecodeError("unclosed '{'", text, start, etc) -end - -local function grok_array(self, text, start, etc) - if text:sub(start,start) ~= '[' then - self:onDecodeError("expected '['", text, start, etc) - end - - local i = skip_whitespace(text, start + 1) -- +1 to skip the '[' - local VALUE = self.strictTypes and self:newArray { } or { } - if text:sub(i,i) == ']' then - return VALUE, i + 1 - end - - local VALUE_INDEX = 1 - - local text_len = text:len() - while i <= text_len do - local val, new_i = grok_one(self, text, i) - - -- can't table.insert(VALUE, val) here because it's a no-op if val is nil - VALUE[VALUE_INDEX] = val - VALUE_INDEX = VALUE_INDEX + 1 - - i = skip_whitespace(text, new_i) - - -- - -- Expect now either ']' to end things, or a ',' to allow us to continue. - -- - local c = text:sub(i,i) - if c == ']' then - return VALUE, i + 1 - end - if text:sub(i, i) ~= ',' then - self:onDecodeError("expected comma or '['", text, i, etc) - end - i = skip_whitespace(text, i + 1) - end - self:onDecodeError("unclosed '['", text, start, etc) -end - - -grok_one = function(self, text, start, etc) - -- Skip any whitespace - start = skip_whitespace(text, start) - - if start > text:len() then - self:onDecodeError("unexpected end of string", text, nil, etc) - end - - if text:find('^"', start) then - return grok_string(self, text, start, etc) - - elseif text:find('^[-0123456789 ]', start) then - return grok_number(self, text, start, etc) - - elseif text:find('^%{', start) then - return grok_object(self, text, start, etc) - - elseif text:find('^%[', start) then - return grok_array(self, text, start, etc) - - elseif text:find('^true', start) then - return true, start + 4 - - elseif text:find('^false', start) then - return false, start + 5 - - elseif text:find('^null', start) then - return nil, start + 4 - - else - self:onDecodeError("can't parse JSON", text, start, etc) - end -end - -function OBJDEF:decode(text, etc) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, etc) - end - - if text == nil then - self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, etc) - elseif type(text) ~= 'string' then - self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, etc) - end - - if text:match('^%s*$') then - return nil - end - - if text:match('^%s*<') then - -- Can't be JSON... we'll assume it's HTML - self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, etc) - end - - -- - -- Ensure that it's not UTF-32 or UTF-16. - -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3), - -- but this package can't handle them. - -- - if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then - self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, etc) - end - - local success, value = pcall(grok_one, self, text, 1, etc) - - if success then - return value - else - -- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert. - if self.assert then - self.assert(false, value) - else - assert(false, value) - end - -- and if we're still here, return a nil and throw the error message on as a second arg - return nil, value - end -end - -local function backslash_replacement_function(c) - if c == "\n" then - return "\\n" - elseif c == "\r" then - return "\\r" - elseif c == "\t" then - return "\\t" - elseif c == "\b" then - return "\\b" - elseif c == "\f" then - return "\\f" - elseif c == '"' then - return '\\"' - elseif c == '\\' then - return '\\\\' - else - return string.format("\\u%04x", c:byte()) - end -end - -local chars_to_be_escaped_in_JSON_string - = '[' - .. '"' -- class sub-pattern to match a double quote - .. '%\\' -- class sub-pattern to match a backslash - .. '%z' -- class sub-pattern to match a null - .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters - .. ']' - -local function json_string_literal(value) - local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function) - return '"' .. newval .. '"' -end - -local function object_or_array(self, T, etc) - -- - -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON - -- object. If there are only numbers, it's a JSON array. - -- - -- If we'll be converting to a JSON object, we'll want to sort the keys so that the - -- end result is deterministic. - -- - local string_keys = { } - local number_keys = { } - local number_keys_must_be_strings = false - local maximum_number_key - - for key in pairs(T) do - if type(key) == 'string' then - table.insert(string_keys, key) - elseif type(key) == 'number' then - table.insert(number_keys, key) - if key <= 0 or key >= math.huge then - number_keys_must_be_strings = true - elseif not maximum_number_key or key > maximum_number_key then - maximum_number_key = key - end - else - self:onEncodeError("can't encode table with a key of type " .. type(key), etc) - end - end - - if #string_keys == 0 and not number_keys_must_be_strings then - -- - -- An empty table, or a numeric-only array - -- - if #number_keys > 0 then - return nil, maximum_number_key -- an array - elseif tostring(T) == "JSON array" then - return nil - elseif tostring(T) == "JSON object" then - return { } - else - -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects - return nil - end - end - - table.sort(string_keys) - - local map - if #number_keys > 0 then - -- - -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array - -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object. - -- - - if self.noKeyConversion then - self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc) - end - - -- - -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings - -- - map = { } - for key, val in pairs(T) do - map[key] = val - end - - table.sort(number_keys) - - -- - -- Throw numeric keys in there as strings - -- - for _, number_key in ipairs(number_keys) do - local string_key = tostring(number_key) - if map[string_key] == nil then - table.insert(string_keys , string_key) - map[string_key] = T[number_key] - else - self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc) - end - end - end - - return string_keys, nil, map -end - --- --- Encode --- --- 'options' is nil, or a table with possible keys: --- pretty -- if true, return a pretty-printed version --- indent -- a string (usually of spaces) used to indent each nested level --- align_keys -- if true, align all the keys when formatting a table --- -local encode_value -- must predeclare because it calls itself -function encode_value(self, value, parents, etc, options, indent) - - if value == nil then - return 'null' - - elseif type(value) == 'string' then - return json_string_literal(value) - - elseif type(value) == 'number' then - if value ~= value then - -- - -- NaN (Not a Number). - -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option. - -- - return "null" - elseif value >= math.huge then - -- - -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should - -- really be a package option. Note: at least with some implementations, positive infinity - -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is. - -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">=" - -- case first. - -- - return "1e+9999" - elseif value <= -math.huge then - -- - -- Negative infinity. - -- JSON has no INF, so we have to fudge the best we can. This should really be a package option. - -- - return "-1e+9999" - else - return tostring(value) - end - - elseif type(value) == 'boolean' then - return tostring(value) - - elseif type(value) ~= 'table' then - return "null" - --self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc) - - else - -- - -- A table to be converted to either a JSON object or array. - -- - local T = value - - if type(options) ~= 'table' then - options = {} - end - if type(indent) ~= 'string' then - indent = "" - end - - if parents[T] then - self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc) - else - parents[T] = true - end - - local result_value - - local object_keys, maximum_number_key, map = object_or_array(self, T, etc) - if maximum_number_key then - -- - -- An array... - -- - local ITEMS = { } - for i = 1, maximum_number_key do - table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent)) - end - - if options.pretty then - result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]" - else - result_value = "[" .. table.concat(ITEMS, ",") .. "]" - end - - elseif object_keys then - -- - -- An object - -- - local TT = map or T - - if options.pretty then - - local KEYS = { } - local max_key_length = 0 - for _, key in ipairs(object_keys) do - local encoded = encode_value(self, tostring(key), parents, etc, options, indent) - if options.align_keys then - max_key_length = math.max(max_key_length, #encoded) - end - table.insert(KEYS, encoded) - end - local key_indent = indent .. tostring(options.indent or "") - local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "") - local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s" - - local COMBINED_PARTS = { } - for i, key in ipairs(object_keys) do - local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent) - table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val)) - end - result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}" - - else - - local PARTS = { } - for _, key in ipairs(object_keys) do - local encoded_val = encode_value(self, TT[key], parents, etc, options, indent) - local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent) - table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val)) - end - result_value = "{" .. table.concat(PARTS, ",") .. "}" - - end - else - -- - -- An empty array/object... we'll treat it as an array, though it should really be an option - -- - result_value = "[]" - end - - parents[T] = false - return result_value - end -end - - -function OBJDEF:encode(value, etc, options) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onEncodeError("JSON:encode must be called in method format", etc) - end - return encode_value(self, value, {}, etc, options or nil) -end - -function OBJDEF:encode_pretty(value, etc, options) - if type(self) ~= 'table' or self.__index ~= OBJDEF then - OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc) - end - return encode_value(self, value, {}, etc, options or default_pretty_options) -end - -function OBJDEF.__tostring() - return "JSON encode/decode package" -end - -OBJDEF.__index = OBJDEF - -function OBJDEF:new(args) - local new = { } - - if args then - for key, val in pairs(args) do - new[key] = val - end - end - - return setmetatable(new, OBJDEF) -end - -json = OBJDEF:new() - --- --- Version history: --- --- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really --- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines --- more flexible, and changed the default encode_pretty() to be more generally useful. --- --- Added a third 'options' argument to the encode() and encode_pretty() routines, to control --- how the encoding takes place. --- --- Updated docs to add assert() call to the loadfile() line, just as good practice so that --- if there is a problem loading JSON.lua, the appropriate error message will percolate up. --- --- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string, --- so that the source of the package, and its version number, are visible in compiled copies. --- --- 20140911.12 Minor lua cleanup. --- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'. --- (Thanks to SmugMug's David Parry for these.) --- --- 20140418.11 JSON nulls embedded within an array were being ignored, such that --- ["1",null,null,null,null,null,"seven"], --- would return --- {1,"seven"} --- It's now fixed to properly return --- {1, nil, nil, nil, nil, nil, "seven"} --- Thanks to "haddock" for catching the error. --- --- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up. --- --- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2", --- and this caused some problems. --- --- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate, --- and had of course diverged (encode_pretty didn't get the fixes that encode got, so --- sometimes produced incorrect results; thanks to Mattie for the heads up). --- --- Handle encoding tables with non-positive numeric keys (unlikely, but possible). --- --- If a table has both numeric and string keys, or its numeric keys are inappropriate --- (such as being non-positive or infinite), the numeric keys are turned into --- string keys appropriate for a JSON object. So, as before, --- JSON:encode({ "one", "two", "three" }) --- produces the array --- ["one","two","three"] --- but now something with mixed key types like --- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) --- instead of throwing an error produces an object: --- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} --- --- To maintain the prior throw-an-error semantics, set --- JSON.noKeyConversion = true --- --- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry. --- --- 20130120.6 Comment update: added a link to the specific page on my blog where this code can --- be found, so that folks who come across the code outside of my blog can find updates --- more easily. --- --- 20111207.5 Added support for the 'etc' arguments, for better error reporting. --- --- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent. --- --- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules: --- --- * When encoding lua for JSON, Sparse numeric arrays are now handled by --- spitting out full arrays, such that --- JSON:encode({"one", "two", [10] = "ten"}) --- returns --- ["one","two",null,null,null,null,null,null,null,"ten"] --- --- In 20100810.2 and earlier, only up to the first non-null value would have been retained. --- --- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999". --- Version 20100810.2 and earlier created invalid JSON in both cases. --- --- * Unicode surrogate pairs are now detected when decoding JSON. --- --- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding --- --- 20100731.1 initial public release --- diff --git a/resources/plugins/base/mist_4_5_107.lua b/resources/plugins/base/mist_4_5_107.lua deleted file mode 100644 index 431848d82..000000000 --- a/resources/plugins/base/mist_4_5_107.lua +++ /dev/null @@ -1,9084 +0,0 @@ ---[[-- -MIST Mission Scripting Tools. -## Description: -MIssion Scripting Tools (MIST) is a collection of Lua functions -and databases that is intended to be a supplement to the standard -Lua functions included in the simulator scripting engine. - -MIST functions and databases provide ready-made solutions to many common -scripting tasks and challenges, enabling easier scripting and saving -mission scripters time. The table mist.flagFuncs contains a set of -Lua functions (that are similar to Slmod functions) that do not -require detailed Lua knowledge to use. - -However, the majority of MIST does require knowledge of the Lua language, -and, if you are going to utilize these components of MIST, it is necessary -that you read the Simulator Scripting Engine guide on the official ED wiki. - -## Links: - -ED Forum Thread: - -##Github: - -Development - -Official Releases - -@script MIST -@author Speed -@author Grimes -@author lukrop -]] -mist = {} - --- don't change these -mist.majorVersion = 4 -mist.minorVersion = 5 -mist.build = 107 - --- forward declaration of log shorthand -local log -local dbLog - -local mistSettings = { - errorPopup = false, -- errors printed by mist logger will create popup warning you - warnPopup = false, - infoPopup = false, - logLevel = 'warn', - dbLog = 'warn', -} - -do -- the main scope - local coroutines = {} - - local tempSpawnedUnits = {} -- birth events added here - local tempSpawnedGroups = {} - local tempSpawnGroupsCounter = 0 - - local mistAddedObjects = {} -- mist.dynAdd unit data added here - local mistAddedGroups = {} -- mist.dynAdd groupdata added here - local writeGroups = {} - local lastUpdateTime = 0 - - local updateAliveUnitsCounter = 0 - local updateTenthSecond = 0 - - local mistGpId = 7000 - local mistUnitId = 7000 - local mistDynAddIndex = {[' air '] = 0, [' hel '] = 0, [' gnd '] = 0, [' bld '] = 0, [' static '] = 0, [' shp '] = 0} - - local scheduledTasks = {} - local taskId = 0 - local idNum = 0 - - mist.nextGroupId = 1 - mist.nextUnitId = 1 - - - - local function initDBs() -- mist.DBs scope - mist.DBs = {} - mist.DBs.markList = {} - mist.DBs.missionData = {} - if env.mission then - - mist.DBs.missionData.startTime = env.mission.start_time - mist.DBs.missionData.theatre = env.mission.theatre - mist.DBs.missionData.version = env.mission.version - mist.DBs.missionData.files = {} - if type(env.mission.resourceCounter) == 'table' then - for fIndex, fData in pairs (env.mission.resourceCounter) do - mist.DBs.missionData.files[#mist.DBs.missionData.files + 1] = mist.utils.deepCopy(fIndex) - end - end - -- if we add more coalition specific data then bullsye should be categorized by coaliton. For now its just the bullseye table - mist.DBs.missionData.bullseye = {} - end - - mist.DBs.zonesByName = {} - mist.DBs.zonesByNum = {} - - - if env.mission.triggers and env.mission.triggers.zones then - for zone_ind, zone_data in pairs(env.mission.triggers.zones) do - if type(zone_data) == 'table' then - local zone = mist.utils.deepCopy(zone_data) - zone.point = {} -- point is used by SSE - zone.point.x = zone_data.x - zone.point.y = 0 - zone.point.z = zone_data.y - zone.properties = {} - if zone_data.properties then - for propInd, prop in pairs(zone_data.properties) do - if prop.value and type(prop.value) == 'string' and prop.value ~= "" then - zone.properties[prop.key] = prop.value - end - end - end - if zone.verticies then -- trust but verify - local r = 0 - for i = 1, #zone.verticies do - local dist = mist.utils.get2DDist(zone.point, zone.verticies[i]) - if dist > r then - r = mist.utils.deepCopy(dist) - end - end - zone.radius = r - - end - - mist.DBs.zonesByName[zone_data.name] = zone - mist.DBs.zonesByNum[#mist.DBs.zonesByNum + 1] = mist.utils.deepCopy(zone) --[[deepcopy so that the zone in zones_by_name and the zone in - zones_by_num se are different objects.. don't want them linked.]] - end - end - end - - mist.DBs.drawingByName = {} - mist.DBs.drawingIndexed = {} - - if env.mission.drawings and env.mission.drawings.layers then - for i = 1, #env.mission.drawings.layers do - local l = env.mission.drawings.layers[i] - - for j = 1, #l.objects do - local copy = mist.utils.deepCopy(l.objects[j]) - --log:warn(copy) - local doOffset = false - copy.layer = l.name - - local theta = copy.angle or 0 - theta = math.rad(theta) - if copy.primitiveType == "Polygon" then - - if copy.polygonMode == 'rect' then - local h, w = copy.height, copy.width - copy.points = {} - copy.points[1] = {x = h/2, y = w/2} - copy.points[2] = {x = -h/2, y = w/2} - copy.points[3] = {x = -h/2, y = -w/2} - copy.points[4] = {x = h/2, y = -w/2} - doOffset = true - elseif copy.polygonMode == "circle" then - copy.points = {x = copy.mapX, y = copy.mapY} - elseif copy.polygonMode == 'oval' then - copy.points = {} - local numPoints = 24 - local angleStep = (math.pi*2)/numPoints - doOffset = true - for v = 1, numPoints do - local pointAngle = v * angleStep - local x = copy.r1 * math.cos(pointAngle) - local y = copy.r2 * math.sin(pointAngle) - - table.insert(copy.points,{x=x,y=y}) - - end - elseif copy.polygonMode == "arrow" then - doOffset = true - end - - - if theta ~= 0 and copy.points and doOffset == true then - - --log:warn('offsetting Values') - for p = 1, #copy.points do - local offset = mist.vec.rotateVec2(copy.points[p], theta) - copy.points[p] = offset - end - --log:warn(copy.points[1]) - end - - elseif copy.primitiveType == "Line" and copy.closed == true then - table.insert(copy.points, mist.utils.deepCopy(copy.points[1])) - end - if copy.points and #copy.points > 1 then - for u = 1, #copy.points do - copy.points[u].x = mist.utils.round(copy.points[u].x + copy.mapX, 2) - copy.points[u].y = mist.utils.round(copy.points[u].y + copy.mapY, 2) - end - - end - if mist.DBs.drawingByName[copy.name] then - log:warn("Drawing by the name of [ $1 ] already exists in DB. Failed to add to mist.DBs.drawingByName.", copy.name) - else - - mist.DBs.drawingByName[copy.name] = copy - end - table.insert(mist.DBs.drawingIndexed, copy) - end - - end - - end - - - mist.DBs.navPoints = {} - mist.DBs.units = {} - --Build mist.db.units and mist.DBs.navPoints - for coa_name_miz, coa_data in pairs(env.mission.coalition) do - local coa_name = coa_name_miz - if string.lower(coa_name_miz) == 'neutrals' then - coa_name = 'neutral' - end - if type(coa_data) == 'table' then - mist.DBs.units[coa_name] = {} - - if coa_data.bullseye then - mist.DBs.missionData.bullseye[coa_name] = {} - mist.DBs.missionData.bullseye[coa_name].x = coa_data.bullseye.x - mist.DBs.missionData.bullseye[coa_name].y = coa_data.bullseye.y - end - -- build nav points DB - mist.DBs.navPoints[coa_name] = {} - if coa_data.nav_points then --navpoints - --mist.debug.writeData (mist.utils.serialize,{'NavPoints',coa_data.nav_points}, 'NavPoints.txt') - for nav_ind, nav_data in pairs(coa_data.nav_points) do - - if type(nav_data) == 'table' then - mist.DBs.navPoints[coa_name][nav_ind] = mist.utils.deepCopy(nav_data) - - mist.DBs.navPoints[coa_name][nav_ind].name = nav_data.callsignStr -- name is a little bit more self-explanatory. - mist.DBs.navPoints[coa_name][nav_ind].point = {} -- point is used by SSE, support it. - mist.DBs.navPoints[coa_name][nav_ind].point.x = nav_data.x - mist.DBs.navPoints[coa_name][nav_ind].point.y = 0 - mist.DBs.navPoints[coa_name][nav_ind].point.z = nav_data.y - end - end - end - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - - local countryName = string.lower(cntry_data.name) - if cntry_data.id and country.names[cntry_data.id] then - countryName = string.lower(country.names[cntry_data.id]) - end - mist.DBs.units[coa_name][countryName] = {} - mist.DBs.units[coa_name][countryName].countryId = cntry_data.id - - if type(cntry_data) == 'table' then --just making sure - - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" or obj_cat_name == "static" then --should be an unncessary check - - local category = obj_cat_name - - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - - mist.DBs.units[coa_name][countryName][category] = {} - - for group_num, group_data in pairs(obj_cat_data.group) do - - if group_data and group_data.units and type(group_data.units) == 'table' then --making sure again- this is a valid group - - mist.DBs.units[coa_name][countryName][category][group_num] = {} - local groupName = group_data.name - if env.mission.version > 7 and env.mission.version < 19 then - groupName = env.getValueDictByKey(groupName) - end - mist.DBs.units[coa_name][countryName][category][group_num].groupName = groupName - mist.DBs.units[coa_name][countryName][category][group_num].groupId = group_data.groupId - mist.DBs.units[coa_name][countryName][category][group_num].category = category - mist.DBs.units[coa_name][countryName][category][group_num].coalition = coa_name - mist.DBs.units[coa_name][countryName][category][group_num].country = countryName - mist.DBs.units[coa_name][countryName][category][group_num].countryId = cntry_data.id - mist.DBs.units[coa_name][countryName][category][group_num].startTime = group_data.start_time - mist.DBs.units[coa_name][countryName][category][group_num].task = group_data.task - mist.DBs.units[coa_name][countryName][category][group_num].hidden = group_data.hidden - - mist.DBs.units[coa_name][countryName][category][group_num].units = {} - - mist.DBs.units[coa_name][countryName][category][group_num].radioSet = group_data.radioSet - mist.DBs.units[coa_name][countryName][category][group_num].uncontrolled = group_data.uncontrolled - mist.DBs.units[coa_name][countryName][category][group_num].frequency = group_data.frequency - mist.DBs.units[coa_name][countryName][category][group_num].modulation = group_data.modulation - - for unit_num, unit_data in pairs(group_data.units) do - local units_tbl = mist.DBs.units[coa_name][countryName][category][group_num].units --pointer to the units table for this group - - units_tbl[unit_num] = {} - if env.mission.version > 7 and env.mission.version < 19 then - units_tbl[unit_num].unitName = env.getValueDictByKey(unit_data.name) - else - units_tbl[unit_num].unitName = unit_data.name - end - units_tbl[unit_num].type = unit_data.type - units_tbl[unit_num].skill = unit_data.skill --will be nil for statics - units_tbl[unit_num].unitId = unit_data.unitId - units_tbl[unit_num].category = category - units_tbl[unit_num].coalition = coa_name - units_tbl[unit_num].country = countryName - units_tbl[unit_num].countryId = cntry_data.id - units_tbl[unit_num].heading = unit_data.heading - units_tbl[unit_num].playerCanDrive = unit_data.playerCanDrive - units_tbl[unit_num].alt = unit_data.alt - units_tbl[unit_num].alt_type = unit_data.alt_type - units_tbl[unit_num].speed = unit_data.speed - units_tbl[unit_num].livery_id = unit_data.livery_id - if unit_data.point then --ME currently does not work like this, but it might one day - units_tbl[unit_num].point = unit_data.point - else - units_tbl[unit_num].point = {} - units_tbl[unit_num].point.x = unit_data.x - units_tbl[unit_num].point.y = unit_data.y - end - units_tbl[unit_num].x = unit_data.x - units_tbl[unit_num].y = unit_data.y - - units_tbl[unit_num].callsign = unit_data.callsign - units_tbl[unit_num].onboard_num = unit_data.onboard_num - units_tbl[unit_num].hardpoint_racks = unit_data.hardpoint_racks - units_tbl[unit_num].psi = unit_data.psi - - - units_tbl[unit_num].groupName = groupName - units_tbl[unit_num].groupId = group_data.groupId - - if unit_data.AddPropAircraft then - units_tbl[unit_num].AddPropAircraft = unit_data.AddPropAircraft - end - - if category == 'static' then - units_tbl[unit_num].categoryStatic = unit_data.category - units_tbl[unit_num].shape_name = unit_data.shape_name - units_tbl[unit_num].linkUnit = unit_data.linkUnit - if unit_data.mass then - units_tbl[unit_num].mass = unit_data.mass - end - - if unit_data.canCargo then - units_tbl[unit_num].canCargo = unit_data.canCargo - end - end - - end --for unit_num, unit_data in pairs(group_data.units) do - end --if group_data and group_data.units then - end --for group_num, group_data in pairs(obj_cat_data.group) do - end --if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then - end --if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" or obj_cat_name == "static" then - end --for obj_cat_name, obj_cat_data in pairs(cntry_data) do - end --if type(cntry_data) == 'table' then - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - - mist.DBs.unitsByName = {} - mist.DBs.unitsById = {} - mist.DBs.unitsByCat = {} - - mist.DBs.unitsByCat.helicopter = {} -- adding default categories - mist.DBs.unitsByCat.plane = {} - mist.DBs.unitsByCat.ship = {} - mist.DBs.unitsByCat.static = {} - mist.DBs.unitsByCat.vehicle = {} - - mist.DBs.unitsByNum = {} - - mist.DBs.groupsByName = {} - mist.DBs.groupsById = {} - mist.DBs.humansByName = {} - mist.DBs.humansById = {} - - mist.DBs.dynGroupsAdded = {} -- will be filled by mist.dbUpdate from dynamically spawned groups - mist.DBs.activeHumans = {} - - mist.DBs.aliveUnits = {} -- will be filled in by the "updateAliveUnits" coroutine in mist.main. - - mist.DBs.removedAliveUnits = {} -- will be filled in by the "updateAliveUnits" coroutine in mist.main. - - mist.DBs.const = {} - - -- not accessible by SSE, must use static list :-/ - mist.DBs.const.callsigns = { - ['NATO'] = { - ['rules'] = { - ['groupLimit'] = 9, - }, - ['AWACS'] = { - ['Overlord'] = 1, - ['Magic'] = 2, - ['Wizard'] = 3, - ['Focus'] = 4, - ['Darkstar'] = 5, - }, - ['TANKER'] = { - ['Texaco'] = 1, - ['Arco'] = 2, - ['Shell'] = 3, - }, - ['TRANSPORT'] = { - ['Heavy'] = 9, - ['Trash'] = 10, - ['Cargo'] = 11, - ['Ascot'] = 12, - ['JTAC'] = { - ['Axeman'] = 1, - ['Darknight'] = 2, - ['Warrior'] = 3, - ['Pointer'] = 4, - ['Eyeball'] = 5, - ['Moonbeam'] = 6, - ['Whiplash'] = 7, - ['Finger'] = 8, - ['Pinpoint'] = 9, - ['Ferret'] = 10, - ['Shaba'] = 11, - ['Playboy'] = 12, - ['Hammer'] = 13, - ['Jaguar'] = 14, - ['Deathstar'] = 15, - ['Anvil'] = 16, - ['Firefly'] = 17, - ['Mantis'] = 18, - ['Badger'] = 19, - }, - ['aircraft'] = { - ['Enfield'] = 1, - ['Springfield'] = 2, - ['Uzi'] = 3, - ['Colt'] = 4, - ['Dodge'] = 5, - ['Ford'] = 6, - ['Chevy'] = 7, - ['Pontiac'] = 8, - }, - - ['unique'] = { - ['A10'] = { - ['Hawg'] = 9, - ['Boar'] = 10, - ['Pig'] = 11, - ['Tusk'] = 12, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'A-10C_2', - 'A-10C', - 'A-10A', - }, - }, - }, - ['f16'] = { - Viper = 9, - Venom = 10, - Lobo = 11, - Cowboy = 12, - Python = 13, - Rattler =14, - Panther = 15, - Wolf = 16, - Weasel = 17, - Wild = 18, - Ninja = 19, - Jedi = 20, - rules = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'F-16C_50', - 'F-16C bl.52d', - 'F-16C bl.50', - 'F-16A MLU', - 'F-16A', - }, - }, - - }, - ['f18'] = { - ['Hornet'] = 9, - ['Squid'] = 10, - ['Ragin'] = 11, - ['Roman'] = 12, - Sting = 13, - Jury =14, - Jokey = 15, - Ram = 16, - Hawk = 17, - Devil = 18, - Check = 19, - Snake = 20, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - - "FA-18C_hornet", - 'F/A-18C', - }, - }, - }, - ['b1'] = { - ['Bone'] = 9, - ['Dark'] = 10, - ['Vader'] = 11, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'B-1B', - }, - }, - }, - ['b52'] = { - ['Buff'] = 9, - ['Dump'] = 10, - ['Kenworth'] = 11, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'B-52H', - }, - }, - }, - ['f15e'] = { - ['Dude'] = 9, - ['Thud'] = 10, - ['Gunny'] = 11, - ['Trek'] = 12, - Sniper = 13, - Sled =14, - Best = 15, - Jazz = 16, - Rage = 17, - Tahoe = 18, - ['rules'] = { - ['canUseAircraft'] = true, - ['appliesTo'] = { - 'F-15E', - --'F-15ERAZBAM', - }, - }, - }, - - }, - }, - }, - } - mist.DBs.const.shapeNames = { - ["Landmine"] = "landmine", - ["FARP CP Blindage"] = "kp_ug", - ["Subsidiary structure C"] = "saray-c", - ["Barracks 2"] = "kazarma2", - ["Small house 2C"] = "dom2c", - ["Military staff"] = "aviashtab", - ["Tech hangar A"] = "ceh_ang_a", - ["Oil derrick"] = "neftevyshka", - ["Tech combine"] = "kombinat", - ["Garage B"] = "garage_b", - ["Airshow_Crowd"] = "Crowd1", - ["Hangar A"] = "angar_a", - ["Repair workshop"] = "tech", - ["Subsidiary structure D"] = "saray-d", - ["FARP Ammo Dump Coating"] = "SetkaKP", - ["Small house 1C area"] = "dom2c-all", - ["Tank 2"] = "airbase_tbilisi_tank_01", - ["Boiler-house A"] = "kotelnaya_a", - ["Workshop A"] = "tec_a", - ["Small werehouse 1"] = "s1", - ["Garage small B"] = "garagh-small-b", - ["Small werehouse 4"] = "s4", - ["Shop"] = "magazin", - ["Subsidiary structure B"] = "saray-b", - ["FARP Fuel Depot"] = "GSM Rus", - ["Coach cargo"] = "wagon-gruz", - ["Electric power box"] = "tr_budka", - ["Tank 3"] = "airbase_tbilisi_tank_02", - ["Red_Flag"] = "H-flag_R", - ["Container red 3"] = "konteiner_red3", - ["Garage A"] = "garage_a", - ["Hangar B"] = "angar_b", - ["Black_Tyre"] = "H-tyre_B", - ["Cafe"] = "stolovaya", - ["Restaurant 1"] = "restoran1", - ["Subsidiary structure A"] = "saray-a", - ["Container white"] = "konteiner_white", - ["Warehouse"] = "sklad", - ["Tank"] = "bak", - ["Railway crossing B"] = "pereezd_small", - ["Subsidiary structure F"] = "saray-f", - ["Farm A"] = "ferma_a", - ["Small werehouse 3"] = "s3", - ["Water tower A"] = "wodokachka_a", - ["Railway station"] = "r_vok_sd", - ["Coach a tank blue"] = "wagon-cisterna_blue", - ["Supermarket A"] = "uniwersam_a", - ["Coach a platform"] = "wagon-platforma", - ["Garage small A"] = "garagh-small-a", - ["TV tower"] = "tele_bash", - ["Comms tower M"] = "tele_bash_m", - ["Small house 1A"] = "domik1a", - ["Farm B"] = "ferma_b", - ["GeneratorF"] = "GeneratorF", - ["Cargo1"] = "ab-212_cargo", - ["Container red 2"] = "konteiner_red2", - ["Subsidiary structure E"] = "saray-e", - ["Coach a passenger"] = "wagon-pass", - ["Black_Tyre_WF"] = "H-tyre_B_WF", - ["Electric locomotive"] = "elektrowoz", - ["Shelter"] = "ukrytie", - ["Coach a tank yellow"] = "wagon-cisterna_yellow", - ["Railway crossing A"] = "pereezd_big", - [".Ammunition depot"] = "SkladC", - ["Small werehouse 2"] = "s2", - ["Windsock"] = "H-Windsock_RW", - ["Shelter B"] = "ukrytie_b", - ["Fuel tank"] = "toplivo-bak", - ["Locomotive"] = "teplowoz", - [".Command Center"] = "ComCenter", - ["Pump station"] = "nasos", - ["Black_Tyre_RF"] = "H-tyre_B_RF", - ["Coach cargo open"] = "wagon-gruz-otkr", - ["Subsidiary structure 3"] = "hozdomik3", - ["FARP Tent"] = "PalatkaB", - ["White_Tyre"] = "H-tyre_W", - ["Subsidiary structure G"] = "saray-g", - ["Container red 1"] = "konteiner_red1", - ["Small house 1B area"] = "domik1b-all", - ["Subsidiary structure 1"] = "hozdomik1", - ["Container brown"] = "konteiner_brown", - ["Small house 1B"] = "domik1b", - ["Subsidiary structure 2"] = "hozdomik2", - ["Chemical tank A"] = "him_bak_a", - ["WC"] = "WC", - ["Small house 1A area"] = "domik1a-all", - ["White_Flag"] = "H-Flag_W", - ["Airshow_Cone"] = "Comp_cone", - ["Bulk Cargo Ship Ivanov"] = "barge-1", - ["Bulk Cargo Ship Yakushev"] = "barge-2", - ["Outpost"]="block", - ["Road outpost"]="block-onroad", - ["Container camo"] = "bw_container_cargo", - ["Tech Hangar A"] = "ceh_ang_a", - ["Bunker 1"] = "dot", - ["Bunker 2"] = "dot2", - ["Tanker Elnya 160"] = "elnya", - ["F-shape barrier"] = "f_bar_cargo", - ["Helipad Single"] = "farp", - ["FARP"] = "farps", - ["Fueltank"] = "fueltank_cargo", - ["Gate"] = "gate", - ["FARP Fuel Depot"] = "gsm rus", - ["Armed house"] = "home1_a", - ["FARP Command Post"] = "kp-ug", - ["Watch Tower Armed"] = "ohr-vyshka", - ["Oiltank"] = "oiltank_cargo", - ["Pipes small"] = "pipes_small_cargo", - ["Pipes big"] = "pipes_big_cargo", - ["Oil platform"] = "plavbaza", - ["Tetrapod"] = "tetrapod_cargo", - ["Fuel tank"] = "toplivo", - ["Trunks long"] = "trunks_long_cargo", - ["Trunks small"] = "trunks_small_cargo", - ["Passenger liner"] = "yastrebow", - ["Passenger boat"] = "zwezdny", - ["Oil rig"] = "oil_platform", - ["Gas platform"] = "gas_platform", - ["Container 20ft"] = "container_20ft", - ["Container 40ft"] = "container_40ft", - ["Downed pilot"] = "cadaver", - ["Parachute"] = "parash", - ["Pilot F15 Parachute"] = "pilot_f15_parachute", - ["Pilot standing"] = "pilot_parashut", - } - - - -- create mist.DBs.oldAliveUnits - -- do - -- local intermediate_alive_units = {} -- between 0 and 0.5 secs old - -- local function make_old_alive_units() -- called every 0.5 secs, makes the old_alive_units DB which is just a copy of alive_units that is 0.5 to 1 sec old - -- if intermediate_alive_units then - -- mist.DBs.oldAliveUnits = mist.utils.deepCopy(intermediate_alive_units) - -- end - -- intermediate_alive_units = mist.utils.deepCopy(mist.DBs.aliveUnits) - -- timer.scheduleFunction(make_old_alive_units, nil, timer.getTime() + 0.5) - -- end - - -- make_old_alive_units() - -- end - - --Build DBs - for coa_name, coa_data in pairs(mist.DBs.units) do - for cntry_name, cntry_data in pairs(coa_data) do - for category_name, category_data in pairs(cntry_data) do - if type(category_data) == 'table' then - for group_ind, group_data in pairs(category_data) do - if type(group_data) == 'table' and group_data.units and type(group_data.units) == 'table' and #group_data.units > 0 then -- OCD paradigm programming - mist.DBs.groupsByName[group_data.groupName] = mist.utils.deepCopy(group_data) - mist.DBs.groupsById[group_data.groupId] = mist.utils.deepCopy(group_data) - for unit_ind, unit_data in pairs(group_data.units) do - mist.DBs.unitsByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) - mist.DBs.unitsById[unit_data.unitId] = mist.utils.deepCopy(unit_data) - - mist.DBs.unitsByCat[unit_data.category] = mist.DBs.unitsByCat[unit_data.category] or {} -- future-proofing against new categories... - table.insert(mist.DBs.unitsByCat[unit_data.category], mist.utils.deepCopy(unit_data)) - --dbLog:info('inserting $1', unit_data.unitName) - table.insert(mist.DBs.unitsByNum, mist.utils.deepCopy(unit_data)) - - if unit_data.skill and (unit_data.skill == "Client" or unit_data.skill == "Player") then - mist.DBs.humansByName[unit_data.unitName] = mist.utils.deepCopy(unit_data) - mist.DBs.humansById[unit_data.unitId] = mist.utils.deepCopy(unit_data) - --if Unit.getByName(unit_data.unitName) then - -- mist.DBs.activeHumans[unit_data.unitName] = mist.utils.deepCopy(unit_data) - -- mist.DBs.activeHumans[unit_data.unitName].playerName = Unit.getByName(unit_data.unitName):getPlayerName() - --end - end - end - end - end - end - end - end - end - - --DynDBs - mist.DBs.MEunits = mist.utils.deepCopy(mist.DBs.units) - mist.DBs.MEunitsByName = mist.utils.deepCopy(mist.DBs.unitsByName) - mist.DBs.MEunitsById = mist.utils.deepCopy(mist.DBs.unitsById) - mist.DBs.MEunitsByCat = mist.utils.deepCopy(mist.DBs.unitsByCat) - mist.DBs.MEunitsByNum = mist.utils.deepCopy(mist.DBs.unitsByNum) - mist.DBs.MEgroupsByName = mist.utils.deepCopy(mist.DBs.groupsByName) - mist.DBs.MEgroupsById = mist.utils.deepCopy(mist.DBs.groupsById) - - mist.DBs.deadObjects = {} - - do - local mt = {} - - function mt.__newindex(t, key, val) - local original_key = key --only for duplicate runtime IDs. - local key_ind = 1 - while mist.DBs.deadObjects[key] do - --dbLog:warn('duplicate runtime id of previously dead object key: $1', key) - key = tostring(original_key) .. ' #' .. tostring(key_ind) - key_ind = key_ind + 1 - end - - if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then - ----dbLog:info('object found in alive_units') - val.objectData = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val.objectPos = pos.p - end - val.objectType = mist.DBs.aliveUnits[val.object.id_].category - - elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units - ----dbLog:info('object found in old_alive_units') - val.objectData = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val.objectPos = pos.p - end - val.objectType = mist.DBs.removedAliveUnits[val.object.id_].category - - else --attempt to determine if static object... - ----dbLog:info('object not found in alive units or old alive units') - local pos = Object.getPosition(val.object) - if pos then - local static_found = false - for ind, static in pairs(mist.DBs.unitsByCat.static) do - if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... - --dbLog:info('correlated dead static object to position') - val.objectData = static - val.objectPos = pos.p - val.objectType = 'static' - static_found = true - break - end - end - if not static_found then - val.objectPos = pos.p - val.objectType = 'building' - end - else - val.objectType = 'unknown' - end - end - rawset(t, key, val) - end - - setmetatable(mist.DBs.deadObjects, mt) - end - - do -- mist unitID funcs - for id, idData in pairs(mist.DBs.unitsById) do - if idData.unitId > mist.nextUnitId then - mist.nextUnitId = mist.utils.deepCopy(idData.unitId) - end - if idData.groupId > mist.nextGroupId then - mist.nextGroupId = mist.utils.deepCopy(idData.groupId) - end - end - end - - - end - - local function updateAliveUnits() -- coroutine function - local lalive_units = mist.DBs.aliveUnits -- local references for faster execution - local lunits = mist.DBs.unitsByNum - local ldeepcopy = mist.utils.deepCopy - local lUnit = Unit - local lremovedAliveUnits = mist.DBs.removedAliveUnits - local updatedUnits = {} - - if #lunits > 0 then - local units_per_run = math.ceil(#lunits/20) - if units_per_run < 5 then - units_per_run = 5 - end - - for i = 1, #lunits do - if lunits[i].category ~= 'static' then -- can't get statics with Unit.getByName :( - local unit = lUnit.getByName(lunits[i].unitName) - if unit then - ----dbLog:info("unit named $1 alive!", lunits[i].unitName) -- spammy - local pos = unit:getPosition() - local newtbl = ldeepcopy(lunits[i]) - if pos then - newtbl.pos = pos.p - end - newtbl.unit = unit - --newtbl.rt_id = unit.id_ - lalive_units[unit.id_] = newtbl - updatedUnits[unit.id_] = true - end - end - if i%units_per_run == 0 then - coroutine.yield() - end - end - -- All units updated, remove any "alive" units that were not updated- they are dead! - for unit_id, unit in pairs(lalive_units) do - if not updatedUnits[unit_id] then - lremovedAliveUnits[unit_id] = unit - lalive_units[unit_id] = nil - end - end - end - end - - local function dbUpdate(event, objType) - --dbLog:info('dbUpdate') - local newTable = {} - newTable.startTime = 0 - if type(event) == 'string' then -- if name of an object. - local newObject - if Group.getByName(event) then - newObject = Group.getByName(event) - elseif StaticObject.getByName(event) then - newObject = StaticObject.getByName(event) - -- log:info('its static') - else - log:warn('$1 is not a Group or Static Object. This should not be possible. Sent category is: $2', event, objType) - return false - end - - newTable.name = newObject:getName() - newTable.groupId = tonumber(newObject:getID()) - newTable.groupName = newObject:getName() - local unitOneRef - if objType == 'static' then - unitOneRef = newObject - newTable.countryId = tonumber(newObject:getCountry()) - newTable.coalitionId = tonumber(newObject:getCoalition()) - newTable.category = 'static' - else - unitOneRef = newObject:getUnits() - if #unitOneRef > 0 and unitOneRef[1] and type(unitOneRef[1]) == 'table' then - newTable.countryId = tonumber(unitOneRef[1]:getCountry()) - newTable.coalitionId = tonumber(unitOneRef[1]:getCoalition()) - newTable.category = tonumber(newObject:getCategory()) - else - log:warn('getUnits failed to return on $1 ; Built Data: $2.', event, newTable) - return false - end - end - for countryData, countryId in pairs(country.id) do - if newTable.country and string.upper(countryData) == string.upper(newTable.country) or countryId == newTable.countryId then - newTable.countryId = countryId - newTable.country = string.lower(countryData) - for coaData, coaId in pairs(coalition.side) do - if coaId == coalition.getCountryCoalition(countryId) then - newTable.coalition = string.lower(coaData) - end - end - end - end - for catData, catId in pairs(Unit.Category) do - if objType == 'group' and Group.getByName(newTable.groupName):isExist() then - if catId == Group.getByName(newTable.groupName):getCategory() then - newTable.category = string.lower(catData) - end - elseif objType == 'static' and StaticObject.getByName(newTable.groupName):isExist() then - if catId == StaticObject.getByName(newTable.groupName):getCategory() then - newTable.category = string.lower(catData) - end - - end - end - local gfound = false - for index, data in pairs(mistAddedGroups) do - if mist.stringMatch(data.name, newTable.groupName) == true then - gfound = true - newTable.task = data.task - newTable.modulation = data.modulation - newTable.uncontrolled = data.uncontrolled - newTable.radioSet = data.radioSet - newTable.hidden = data.hidden - newTable.startTime = data.start_time - mistAddedGroups[index] = nil - end - end - - if gfound == false then - newTable.uncontrolled = false - newTable.hidden = false - end - - newTable.units = {} - if objType == 'group' then - for unitId, unitData in pairs(unitOneRef) do - newTable.units[unitId] = {} - newTable.units[unitId].unitName = unitData:getName() - - newTable.units[unitId].x = mist.utils.round(unitData:getPosition().p.x) - newTable.units[unitId].y = mist.utils.round(unitData:getPosition().p.z) - newTable.units[unitId].point = {} - newTable.units[unitId].point.x = newTable.units[unitId].x - newTable.units[unitId].point.y = newTable.units[unitId].y - newTable.units[unitId].alt = mist.utils.round(unitData:getPosition().p.y) - newTable.units[unitId].speed = mist.vec.mag(unitData:getVelocity()) - - newTable.units[unitId].heading = mist.getHeading(unitData, true) - - newTable.units[unitId].type = unitData:getTypeName() - newTable.units[unitId].unitId = tonumber(unitData:getID()) - - - newTable.units[unitId].groupName = newTable.groupName - newTable.units[unitId].groupId = newTable.groupId - newTable.units[unitId].countryId = newTable.countryId - newTable.units[unitId].coalitionId = newTable.coalitionId - newTable.units[unitId].coalition = newTable.coalition - newTable.units[unitId].country = newTable.country - local found = false - for index, data in pairs(mistAddedObjects) do - if mist.stringMatch(data.name, newTable.units[unitId].unitName) == true then - found = true - newTable.units[unitId].livery_id = data.livery_id - newTable.units[unitId].skill = data.skill - newTable.units[unitId].alt_type = data.alt_type - newTable.units[unitId].callsign = data.callsign - newTable.units[unitId].psi = data.psi - mistAddedObjects[index] = nil - end - if found == false then - newTable.units[unitId].skill = "High" - newTable.units[unitId].alt_type = "BARO" - end - if newTable.units[unitId].alt_type == "RADIO" then -- raw postition MSL was grabbed for group, but spawn is AGL, so re-offset it - newTable.units[unitId].alt = (newTable.units[unitId].alt - land.getHeight({x = newTable.units[unitId].x, y = newTable.units[unitId].y})) - end - end - - end - else -- its a static - newTable.category = 'static' - newTable.units[1] = {} - newTable.units[1].unitName = newObject:getName() - newTable.units[1].category = 'static' - newTable.units[1].x = mist.utils.round(newObject:getPosition().p.x) - newTable.units[1].y = mist.utils.round(newObject:getPosition().p.z) - newTable.units[1].point = {} - newTable.units[1].point.x = newTable.units[1].x - newTable.units[1].point.y = newTable.units[1].y - newTable.units[1].alt = mist.utils.round(newObject:getPosition().p.y) - newTable.units[1].heading = mist.getHeading(newObject, true) - newTable.units[1].type = newObject:getTypeName() - newTable.units[1].unitId = tonumber(newObject:getID()) - newTable.units[1].groupName = newTable.name - newTable.units[1].groupId = newTable.groupId - newTable.units[1].countryId = newTable.countryId - newTable.units[1].country = newTable.country - newTable.units[1].coalitionId = newTable.coalitionId - newTable.units[1].coalition = newTable.coalition - if newObject:getCategory() == 6 and newObject:getCargoDisplayName() then - local mass = newObject:getCargoDisplayName() - mass = string.gsub(mass, ' ', '') - mass = string.gsub(mass, 'kg', '') - newTable.units[1].mass = tonumber(mass) - newTable.units[1].categoryStatic = 'Cargos' - newTable.units[1].canCargo = true - newTable.units[1].shape_name = 'ab-212_cargo' - end - - ----- search mist added objects for extra data if applicable - for index, data in pairs(mistAddedObjects) do - if mist.stringMatch(data.name, newTable.units[1].unitName) == true then - newTable.units[1].shape_name = data.shape_name -- for statics - newTable.units[1].livery_id = data.livery_id - newTable.units[1].airdromeId = data.airdromeId - newTable.units[1].mass = data.mass - newTable.units[1].canCargo = data.canCargo - newTable.units[1].categoryStatic = data.categoryStatic - newTable.units[1].type = data.type - newTable.units[1].linkUnit = data.linkUnit - - mistAddedObjects[index] = nil - break - end - end - end - end - --mist.debug.writeData(mist.utils.serialize,{'msg', newTable}, timer.getAbsTime() ..'Group.lua') - newTable.timeAdded = timer.getAbsTime() -- only on the dynGroupsAdded table. For other reference, see start time - --mist.debug.dumpDBs() - --end - --dbLog:info('endDbUpdate') - return newTable - end - - --[[DB update code... FRACK. I need to refactor some of it. - - The problem is that the DBs need to account better for shared object names. Needs to write over some data and outright remove other. - - If groupName is used then entire group needs to be rewritten - what to do with old groups units DB entries?. Names cant be assumed to be the same. - - - -- new spawn event check. - -- event handler filters everything into groups: tempSpawnedGroups - -- this function then checks DBs to see if data has changed - ]] - local function checkSpawnedEventsNew() - if tempSpawnGroupsCounter > 0 then - --[[local updatesPerRun = math.ceil(#tempSpawnedGroupsCounter/20) - if updatesPerRun < 5 then - updatesPerRun = 5 - end]] - - --dbLog:info('iterate') - for name, gData in pairs(tempSpawnedGroups) do - --env.info(name) - --dbLog:info(gData) - local updated = false - local stillExists = false - if not gData.checked then - tempSpawnedGroups[name].checked = true -- so if there was an error it will get cleared. - local _g = gData.gp or Group.getByName(name) - if mist.DBs.groupsByName[name] then - -- first check group level properties, groupId, countryId, coalition - --dbLog:info('Found in DBs, check if updated') - local dbTable = mist.DBs.groupsByName[name] - --dbLog:info(dbTable) - if gData.type ~= 'static' then - -- dbLog:info('Not static') - - if _g and _g:isExist() == true then - stillExists = true - local _u = _g:getUnit(1) - - if _u and (dbTable.groupId ~= tonumber(_g:getID()) or _u:getCountry() ~= dbTable.countryId or _u:getCoalition() ~= dbTable.coaltionId) then - --dbLog:info('Group Data mismatch') - updated = true - else - -- dbLog:info('No Mismatch') - end - else - dbLog:warn('$1 : Group was not accessible', name) - end - end - end - --dbLog:info('Updated: $1', updated) - if updated == false and gData.type ~= 'static' then -- time to check units - --dbLog:info('No Group Mismatch, Check Units') - if _g and _g:isExist() == true then - stillExists = true - for index, uObject in pairs(_g:getUnits()) do - --dbLog:info(index) - if mist.DBs.unitsByName[uObject:getName()] then - --dbLog:info('UnitByName table exists') - local uTable = mist.DBs.unitsByName[uObject:getName()] - if tonumber(uObject:getID()) ~= uTable.unitId or uObject:getTypeName() ~= uTable.type then - --dbLog:info('Unit Data mismatch') - updated = true - break - end - end - end - end - else - stillExists = true - end - - if stillExists == true and (updated == true or not mist.DBs.groupsByName[name]) then - --dbLog:info('Get Table') - local dbData = dbUpdate(name, gData.type) - if dbData and type(dbData) == 'table' then - writeGroups[#writeGroups+1] = {data = dbData, isUpdated = updated} - end - end - -- Work done, so remove - end - tempSpawnedGroups[name] = nil - tempSpawnGroupsCounter = tempSpawnGroupsCounter - 1 - end - end - end - - local function updateDBTables() - local i = #writeGroups - - local savesPerRun = math.ceil(i/10) - if savesPerRun < 5 then - savesPerRun = 5 - end - if i > 0 then - --dbLog:info('updateDBTables') - local ldeepCopy = mist.utils.deepCopy - for x = 1, i do - --dbLog:info(writeGroups[x]) - local newTable = writeGroups[x].data - local updated = writeGroups[x].isUpdated - local mistCategory - if type(newTable.category) == 'string' then - mistCategory = string.lower(newTable.category) - end - - if string.upper(newTable.category) == 'GROUND_UNIT' then - mistCategory = 'vehicle' - newTable.category = mistCategory - elseif string.upper(newTable.category) == 'AIRPLANE' then - mistCategory = 'plane' - newTable.category = mistCategory - elseif string.upper(newTable.category) == 'HELICOPTER' then - mistCategory = 'helicopter' - newTable.category = mistCategory - elseif string.upper(newTable.category) == 'SHIP' then - mistCategory = 'ship' - newTable.category = mistCategory - end - --dbLog:info('Update unitsBy') - for newId, newUnitData in pairs(newTable.units) do - --dbLog:info(newId) - newUnitData.category = mistCategory - if newUnitData.unitId then - --dbLog:info('byId') - mist.DBs.unitsById[tonumber(newUnitData.unitId)] = ldeepCopy(newUnitData) - end - --dbLog:info(updated) - if mist.DBs.unitsByName[newUnitData.unitName] and updated == true then--if unit existed before and something was updated, write over the entry for a given unit name just in case. - --dbLog:info('Updating Unit Tables') - for i = 1, #mist.DBs.unitsByCat[mistCategory] do - if mist.DBs.unitsByCat[mistCategory][i].unitName == newUnitData.unitName then - --dbLog:info('Entry Found, Rewriting for unitsByCat') - mist.DBs.unitsByCat[mistCategory][i] = ldeepCopy(newUnitData) - break - end - end - for i = 1, #mist.DBs.unitsByNum do - if mist.DBs.unitsByNum[i].unitName == newUnitData.unitName then - --dbLog:info('Entry Found, Rewriting for unitsByNum') - mist.DBs.unitsByNum[i] = ldeepCopy(newUnitData) - break - end - end - - else - --dbLog:info('Unitname not in use, add as normal') - mist.DBs.unitsByCat[mistCategory][#mist.DBs.unitsByCat[mistCategory] + 1] = ldeepCopy(newUnitData) - mist.DBs.unitsByNum[#mist.DBs.unitsByNum + 1] = ldeepCopy(newUnitData) - end - mist.DBs.unitsByName[newUnitData.unitName] = ldeepCopy(newUnitData) - - - end - -- this is a really annoying DB to populate. Gotta create new tables in case its missing - --dbLog:info('write mist.DBs.units') - if not mist.DBs.units[newTable.coalition] then - mist.DBs.units[newTable.coalition] = {} - end - - if not mist.DBs.units[newTable.coalition][newTable.country] then - mist.DBs.units[newTable.coalition][(newTable.country)] = {} - mist.DBs.units[newTable.coalition][(newTable.country)].countryId = newTable.countryId - end - if not mist.DBs.units[newTable.coalition][newTable.country][mistCategory] then - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] = {} - end - - if updated == true then - --dbLog:info('Updating DBsUnits') - for i = 1, #mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] do - if mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][i].groupName == newTable.groupName then - --dbLog:info('Entry Found, Rewriting') - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][i] = ldeepCopy(newTable) - break - end - end - else - mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory][#mist.DBs.units[newTable.coalition][(newTable.country)][mistCategory] + 1] = ldeepCopy(newTable) - end - - - if newTable.groupId then - mist.DBs.groupsById[newTable.groupId] = ldeepCopy(newTable) - end - - mist.DBs.groupsByName[newTable.name] = ldeepCopy(newTable) - mist.DBs.dynGroupsAdded[#mist.DBs.dynGroupsAdded + 1] = ldeepCopy(newTable) - - writeGroups[x] = nil - if x%savesPerRun == 0 then - coroutine.yield() - end - end - if timer.getTime() > lastUpdateTime then - lastUpdateTime = timer.getTime() - end - --dbLog:info('endUpdateTables') - end - end - - local function groupSpawned(event) - -- dont need to add units spawned in at the start of the mission if mist is loaded in init line - if event.id == world.event.S_EVENT_BIRTH and timer.getTime0() < timer.getAbsTime() then - --log:info('unitSpawnEvent') - --log:info(event) - --log:info(event.initiator:getTypeName()) - --table.insert(tempSpawnedUnits,(event.initiator)) - ------- - -- New functionality below. - ------- - if Object.getCategory(event.initiator) == 1 and not Unit.getPlayerName(event.initiator) then -- simple player check, will need to later check to see if unit was spawned with a player in a flight - --log:info('Object is a Unit') - if Unit.getGroup(event.initiator) then - -- log:info(Unit.getGroup(event.initiator):getName()) - local g = Unit.getGroup(event.initiator) - if not tempSpawnedGroups[g:getName()] then - --log:info('added') - tempSpawnedGroups[g:getName()] = {type = 'group', gp = g} - tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1 - end - else - log:error('Group not accessible by unit in event handler. This is a DCS bug') - end - elseif Object.getCategory(event.initiator) == 3 or Object.getCategory(event.initiator) == 6 then - --log:info('Object is Static') - tempSpawnedGroups[StaticObject.getName(event.initiator)] = {type = 'static'} - tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1 - end - - - end - end - - local function doScheduledFunctions() - local i = 1 - while i <= #scheduledTasks do - if not scheduledTasks[i].rep then -- not a repeated process - if scheduledTasks[i].t <= timer.getTime() then - local task = scheduledTasks[i] -- local reference - table.remove(scheduledTasks, i) - local err, errmsg = pcall(task.f, unpack(task.vars, 1, table.maxn(task.vars))) - if not err then - log:error('Error in scheduled function: $1', errmsg) - end - --task.f(unpack(task.vars, 1, table.maxn(task.vars))) -- do the task, do not increment i - else - i = i + 1 - end - else - if scheduledTasks[i].st and scheduledTasks[i].st <= timer.getTime() then --if a stoptime was specified, and the stop time exceeded - table.remove(scheduledTasks, i) -- stop time exceeded, do not execute, do not increment i - elseif scheduledTasks[i].t <= timer.getTime() then - local task = scheduledTasks[i] -- local reference - task.t = timer.getTime() + task.rep --schedule next run - local err, errmsg = pcall(task.f, unpack(task.vars, 1, table.maxn(task.vars))) - if not err then - log:error('Error in scheduled function: $1' .. errmsg) - end - --scheduledTasks[i].f(unpack(scheduledTasks[i].vars, 1, table.maxn(scheduledTasks[i].vars))) -- do the task - i = i + 1 - else - i = i + 1 - end - end - end - end - - -- Event handler to start creating the dead_objects table - local function addDeadObject(event) - if event.id == world.event.S_EVENT_DEAD or event.id == world.event.S_EVENT_CRASH then - if event.initiator and event.initiator.id_ and event.initiator.id_ > 0 then - - local id = event.initiator.id_ -- initial ID, could change if there is a duplicate id_ already dead. - local val = {object = event.initiator} -- the new entry in mist.DBs.deadObjects. - - local original_id = id --only for duplicate runtime IDs. - local id_ind = 1 - while mist.DBs.deadObjects[id] do - --log:info('duplicate runtime id of previously dead object id: $1', id) - id = tostring(original_id) .. ' #' .. tostring(id_ind) - id_ind = id_ind + 1 - end - - if mist.DBs.aliveUnits and mist.DBs.aliveUnits[val.object.id_] then - --log:info('object found in alive_units') - val.objectData = mist.utils.deepCopy(mist.DBs.aliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val.objectPos = pos.p - end - val.objectType = mist.DBs.aliveUnits[val.object.id_].category - --[[if mist.DBs.activeHumans[Unit.getName(val.object)] then - --trigger.action.outText('remove via death: ' .. Unit.getName(val.object),20) - mist.DBs.activeHumans[Unit.getName(val.object)] = nil - end]] - elseif mist.DBs.removedAliveUnits and mist.DBs.removedAliveUnits[val.object.id_] then -- it didn't exist in alive_units, check old_alive_units - --log:info('object found in old_alive_units') - val.objectData = mist.utils.deepCopy(mist.DBs.removedAliveUnits[val.object.id_]) - local pos = Object.getPosition(val.object) - if pos then - val.objectPos = pos.p - end - val.objectType = mist.DBs.removedAliveUnits[val.object.id_].category - - else --attempt to determine if static object... - --log:info('object not found in alive units or old alive units') - local pos = Object.getPosition(val.object) - if pos then - local static_found = false - for ind, static in pairs(mist.DBs.unitsByCat.static) do - if ((pos.p.x - static.point.x)^2 + (pos.p.z - static.point.y)^2)^0.5 < 0.1 then --really, it should be zero... - --log:info('correlated dead static object to position') - val.objectData = static - val.objectPos = pos.p - val.objectType = 'static' - static_found = true - break - end - end - if not static_found then - val.objectPos = pos.p - val.objectType = 'building' - end - else - val.objectType = 'unknown' - end - end - mist.DBs.deadObjects[id] = val - end - end - end - - --[[ - local function addClientsToActive(event) - if event.id == world.event.S_EVENT_PLAYER_ENTER_UNIT or event.id == world.event.S_EVENT_BIRTH then - log:info(event) - if Unit.getPlayerName(event.initiator) then - log:info(Unit.getPlayerName(event.initiator)) - local newU = mist.utils.deepCopy(mist.DBs.unitsByName[Unit.getName(event.initiator)]) - newU.playerName = Unit.getPlayerName(event.initiator) - mist.DBs.activeHumans[Unit.getName(event.initiator)] = newU - --trigger.action.outText('added: ' .. Unit.getName(event.initiator), 20) - end - elseif event.id == world.event.S_EVENT_PLAYER_LEAVE_UNIT and event.initiator then - if mist.DBs.activeHumans[Unit.getName(event.initiator)] then - mist.DBs.activeHumans[Unit.getName(event.initiator)] = nil - -- trigger.action.outText('removed via control: ' .. Unit.getName(event.initiator), 20) - end - end - end - - mist.addEventHandler(addClientsToActive) - ]] - local function verifyDB() - --log:warn('verfy Run') - for coaName, coaId in pairs(coalition.side) do - --env.info(coaName) - local gps = coalition.getGroups(coaId) - for i = 1, #gps do - if gps[i] and Group.getSize(gps[i]) > 0 then - local gName = Group.getName(gps[i]) - if not mist.DBs.groupsByName[gName] then - --env.info(Unit.getID(gUnits[j]) .. ' Not found in DB yet') - if not tempSpawnedGroups[gName] then - --dbLog:info('added') - tempSpawnedGroups[gName] = {type = 'group', gp = gps[i]} - tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1 - end - end - end - end - local st = coalition.getStaticObjects(coaId) - for i = 1, #st do - local s = st[i] - if StaticObject.isExist(s) then - local name = s:getName() - if not mist.DBs.unitsByName[name] then - dbLog:warn('$1 Not found in DB yet. ID: $2', name, StaticObject.getID(s)) - if string.len(name) > 0 then -- because in this mission someone sent the name was returning as an empty string. Gotta be careful. - tempSpawnedGroups[s:getName()] = {type = 'static'} - tempSpawnGroupsCounter = tempSpawnGroupsCounter + 1 - end - end - end - end - - end - - end - - - --- init function. - -- creates logger, adds default event handler - -- and calls main the first time. - -- @function mist.init - function mist.init() - - -- create logger - mist.log = mist.Logger:new("MIST", mistSettings.logLevel) - dbLog = mist.Logger:new('MISTDB', 'warn') - - log = mist.log -- log shorthand - -- set warning log level, showing only - -- warnings and errors - --log:setLevel("warning") - - log:info("initializing databases") - initDBs() - - -- add event handler for group spawns - mist.addEventHandler(groupSpawned) - mist.addEventHandler(addDeadObject) - - log:warn('Init time: $1', timer.getTime()) - - -- call main the first time therafter it reschedules itself. - mist.main() - --log:msg('MIST version $1.$2.$3 loaded', mist.majorVersion, mist.minorVersion, mist.build) - - mist.scheduleFunction(verifyDB, {}, timer.getTime() + 1) - return - end - - --- The main function. - -- Run 100 times per second. - -- You shouldn't call this function. - function mist.main() - timer.scheduleFunction(mist.main, {}, timer.getTime() + 0.01) --reschedule first in case of Lua error - - updateTenthSecond = updateTenthSecond + 1 - if updateTenthSecond == 20 then - updateTenthSecond = 0 - - checkSpawnedEventsNew() - - if not coroutines.updateDBTables then - coroutines.updateDBTables = coroutine.create(updateDBTables) - end - - coroutine.resume(coroutines.updateDBTables) - - if coroutine.status(coroutines.updateDBTables) == 'dead' then - coroutines.updateDBTables = nil - end - end - - --updating alive units - updateAliveUnitsCounter = updateAliveUnitsCounter + 1 - if updateAliveUnitsCounter == 5 then - updateAliveUnitsCounter = 0 - - if not coroutines.updateAliveUnits then - coroutines.updateAliveUnits = coroutine.create(updateAliveUnits) - end - - coroutine.resume(coroutines.updateAliveUnits) - - if coroutine.status(coroutines.updateAliveUnits) == 'dead' then - coroutines.updateAliveUnits = nil - end - end - - doScheduledFunctions() - end -- end of mist.main - - --- Returns next unit id. - -- @treturn number next unit id. - function mist.getNextUnitId() - mist.nextUnitId = mist.nextUnitId + 1 - if mist.nextUnitId > 6900 and mist.nextUnitId < 30000 then - mist.nextUnitId = 30000 - end - return mist.utils.deepCopy(mist.nextUnitId) - end - - --- Returns next group id. - -- @treturn number next group id. - function mist.getNextGroupId() - mist.nextGroupId = mist.nextGroupId + 1 - if mist.nextGroupId > 6900 and mist.nextGroupId < 30000 then - mist.nextGroupId = 30000 - end - return mist.utils.deepCopy(mist.nextGroupId) - end - - --- Returns timestamp of last database update. - -- @treturn timestamp of last database update - function mist.getLastDBUpdateTime() - return lastUpdateTime - end - - --- Spawns a static object to the game world. - -- @todo write good docs - -- @tparam table staticObj table containing data needed for the object creation - function mist.dynAddStatic(n) - --log:info(newObj) - local newObj = mist.utils.deepCopy(n) - if newObj.units and newObj.units[1] then -- if its mist format - for entry, val in pairs(newObj.units[1]) do - if newObj[entry] and newObj[entry] ~= val or not newObj[entry] then - newObj[entry] = val - end - end - end - --log:info(newObj) - - local cntry = newObj.country - if newObj.countryId then - cntry = newObj.countryId - end - - local newCountry = '' - - for countryId, countryName in pairs(country.name) do - if type(cntry) == 'string' then - cntry = cntry:gsub("%s+", "_") - if tostring(countryName) == string.upper(cntry) then - newCountry = countryName - end - elseif type(cntry) == 'number' then - if countryId == cntry then - newCountry = countryName - end - end - end - - if newCountry == '' then - log:error("Country not found: $1", cntry) - return false - end - - if newObj.clone or not newObj.groupId then - mistGpId = mistGpId + 1 - newObj.groupId = mistGpId - end - - if newObj.clone or not newObj.unitId then - mistUnitId = mistUnitId + 1 - newObj.unitId = mistUnitId - end - - - newObj.name = newObj.name or newObj.unitName - - if newObj.clone or not newObj.name then - mistDynAddIndex[' static '] = mistDynAddIndex[' static '] + 1 - newObj.name = (newCountry .. ' static ' .. mistDynAddIndex[' static ']) - end - - if not newObj.dead then - newObj.dead = false - end - - if not newObj.heading then - newObj.heading = math.random(360) - end - - if newObj.categoryStatic then - newObj.category = newObj.categoryStatic - end - if newObj.mass then - newObj.category = 'Cargos' - end - - if newObj.shapeName then - newObj.shape_name = newObj.shapeName - end - - if not newObj.shape_name then - log:info('shape_name not present') - if mist.DBs.const.shapeNames[newObj.type] then - newObj.shape_name = mist.DBs.const.shapeNames[newObj.type] - end - end - - mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newObj) - if newObj.x and newObj.y and newObj.type and type(newObj.x) == 'number' and type(newObj.y) == 'number' and type(newObj.type) == 'string' then - --log:warn(newObj) - coalition.addStaticObject(country.id[newCountry], newObj) - - return newObj - end - log:error("Failed to add static object due to missing or incorrect value. X: $1, Y: $2, Type: $3", newObj.x, newObj.y, newObj.type) - return false - end - - --- Spawns a dynamic group into the game world. - -- Same as coalition.add function in SSE. checks the passed data to see if its valid. - -- Will generate groupId, groupName, unitId, and unitName if needed - -- @tparam table newGroup table containting values needed for spawning a group. - function mist.dynAdd(ng) - - local newGroup = mist.utils.deepCopy(ng) - --log:warn(newGroup) - --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroupOrig.lua') - local cntry = newGroup.country - if newGroup.countryId then - cntry = newGroup.countryId - end - - local groupType = newGroup.category - local newCountry = '' - -- validate data - for countryId, countryName in pairs(country.name) do - if type(cntry) == 'string' then - cntry = cntry:gsub("%s+", "_") - if tostring(countryName) == string.upper(cntry) then - newCountry = countryName - end - elseif type(cntry) == 'number' then - if countryId == cntry then - newCountry = countryName - end - end - end - - if newCountry == '' then - log:error("Country not found: $1", cntry) - return false - end - - local newCat = '' - for catName, catId in pairs(Unit.Category) do - if type(groupType) == 'string' then - if tostring(catName) == string.upper(groupType) then - newCat = catName - end - elseif type(groupType) == 'number' then - if catId == groupType then - newCat = catName - end - end - - if catName == 'GROUND_UNIT' and (string.upper(groupType) == 'VEHICLE' or string.upper(groupType) == 'GROUND') then - newCat = 'GROUND_UNIT' - elseif catName == 'AIRPLANE' and string.upper(groupType) == 'PLANE' then - newCat = 'AIRPLANE' - end - end - local typeName - if newCat == 'GROUND_UNIT' then - typeName = ' gnd ' - elseif newCat == 'AIRPLANE' then - typeName = ' air ' - elseif newCat == 'HELICOPTER' then - typeName = ' hel ' - elseif newCat == 'SHIP' then - typeName = ' shp ' - elseif newCat == 'BUILDING' then - typeName = ' bld ' - end - if newGroup.clone or not newGroup.groupId then - mistDynAddIndex[typeName] = mistDynAddIndex[typeName] + 1 - mistGpId = mistGpId + 1 - newGroup.groupId = mistGpId - end - if newGroup.groupName or newGroup.name then - if newGroup.groupName then - newGroup.name = newGroup.groupName - elseif newGroup.name then - newGroup.name = newGroup.name - end - end - - if newGroup.clone and mist.DBs.groupsByName[newGroup.name] or not newGroup.name then - --if newGroup.baseName then - -- idea of later. So custmozed naming can be created - -- else - newGroup.name = tostring(newCountry .. tostring(typeName) .. mistDynAddIndex[typeName]) - --end - end - - if not newGroup.hidden then - newGroup.hidden = false - end - - if not newGroup.visible then - newGroup.visible = false - end - - if (newGroup.start_time and type(newGroup.start_time) ~= 'number') or not newGroup.start_time then - if newGroup.startTime then - newGroup.start_time = mist.utils.round(newGroup.startTime) - else - newGroup.start_time = 0 - end - end - - - for unitIndex, unitData in pairs(newGroup.units) do - local originalName = newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name - if newGroup.clone or not unitData.unitId then - mistUnitId = mistUnitId + 1 - newGroup.units[unitIndex].unitId = mistUnitId - end - if newGroup.units[unitIndex].unitName or newGroup.units[unitIndex].name then - if newGroup.units[unitIndex].unitName then - newGroup.units[unitIndex].name = newGroup.units[unitIndex].unitName - elseif newGroup.units[unitIndex].name then - newGroup.units[unitIndex].name = newGroup.units[unitIndex].name - end - end - if newGroup.clone or not unitData.name then - newGroup.units[unitIndex].name = tostring(newGroup.name .. ' unit' .. unitIndex) - end - - if not unitData.skill then - newGroup.units[unitIndex].skill = 'Random' - end - - if newCat == 'AIRPLANE' or newCat == 'HELICOPTER' then - if newGroup.units[unitIndex].alt_type and newGroup.units[unitIndex].alt_type ~= 'BARO' or not newGroup.units[unitIndex].alt_type then - newGroup.units[unitIndex].alt_type = 'RADIO' - end - if not unitData.speed then - if newCat == 'AIRPLANE' then - newGroup.units[unitIndex].speed = 150 - elseif newCat == 'HELICOPTER' then - newGroup.units[unitIndex].speed = 60 - end - end - if not unitData.payload then - newGroup.units[unitIndex].payload = mist.getPayload(originalName) - end - if not unitData.alt then - if newCat == 'AIRPLANE' then - newGroup.units[unitIndex].alt = 2000 - newGroup.units[unitIndex].alt_type = 'RADIO' - newGroup.units[unitIndex].speed = 150 - elseif newCat == 'HELICOPTER' then - newGroup.units[unitIndex].alt = 500 - newGroup.units[unitIndex].alt_type = 'RADIO' - newGroup.units[unitIndex].speed = 60 - end - end - - elseif newCat == 'GROUND_UNIT' then - if nil == unitData.playerCanDrive then - unitData.playerCanDrive = true - end - - end - mistAddedObjects[#mistAddedObjects + 1] = mist.utils.deepCopy(newGroup.units[unitIndex]) - end - mistAddedGroups[#mistAddedGroups + 1] = mist.utils.deepCopy(newGroup) - if newGroup.route then - if newGroup.route and not newGroup.route.points then - if newGroup.route[1] then - local copyRoute = mist.utils.deepCopy(newGroup.route) - newGroup.route = {} - newGroup.route.points = copyRoute - end - end - else -- if aircraft and no route assigned. make a quick and stupid route so AI doesnt RTB immediately - --if newCat == 'AIRPLANE' or newCat == 'HELICOPTER' then - newGroup.route = {} - newGroup.route.points = {} - newGroup.route.points[1] = {} - --end - end - newGroup.country = newCountry - - -- update and verify any self tasks - if newGroup.route and newGroup.route.points then - for i, pData in pairs(newGroup.route.points) do - if pData.task and pData.task.params and pData.task.params.tasks and #pData.task.params.tasks > 0 then - for tIndex, tData in pairs(pData.task.params.tasks) do - if tData.params and tData.params.action then - if tData.params.action.id == "EPLRS" then - tData.params.action.params.groupId = newGroup.groupId - elseif tData.params.action.id == "ActivateBeacon" or tData.params.action.id == "ActivateICLS" then - tData.params.action.params.unitId = newGroup.units[1].unitId - end - end - end - end - - end - end - --mist.debug.writeData(mist.utils.serialize,{'msg', newGroup}, 'newGroupPushedToAddGroup.lua') - --log:warn(newGroup) - -- sanitize table - newGroup.groupName = nil - newGroup.clone = nil - newGroup.category = nil - newGroup.country = nil - - newGroup.tasks = {} - - for unitIndex, unitData in pairs(newGroup.units) do - newGroup.units[unitIndex].unitName = nil - end - - coalition.addGroup(country.id[newCountry], Unit.Category[newCat], newGroup) - - return newGroup - - end - - --- Schedules a function. - -- Modified Slmod task scheduler, superior to timer.scheduleFunction - -- @tparam function f function to schedule - -- @tparam table vars array containing all parameters passed to the function - -- @tparam number t time in seconds from mission start to schedule the function to. - -- @tparam[opt] number rep time between repetitions of the function - -- @tparam[opt] number st time in seconds from mission start at which the function - -- should stop to be rescheduled. - -- @treturn number scheduled function id. - function mist.scheduleFunction(f, vars, t, rep, st) - --verify correct types - assert(type(f) == 'function', 'variable 1, expected function, got ' .. type(f)) - assert(type(vars) == 'table' or vars == nil, 'variable 2, expected table or nil, got ' .. type(f)) - assert(type(t) == 'number', 'variable 3, expected number, got ' .. type(t)) - assert(type(rep) == 'number' or rep == nil, 'variable 4, expected number or nil, got ' .. type(rep)) - assert(type(st) == 'number' or st == nil, 'variable 5, expected number or nil, got ' .. type(st)) - if not vars then - vars = {} - end - taskId = taskId + 1 - table.insert(scheduledTasks, {f = f, vars = vars, t = t, rep = rep, st = st, id = taskId}) - return taskId - end - - --- Removes a scheduled function. - -- @tparam number id function id - -- @treturn boolean true if function was successfully removed, false otherwise. - function mist.removeFunction(id) - local i = 1 - while i <= #scheduledTasks do - if scheduledTasks[i].id == id then - table.remove(scheduledTasks, i) - return true - else - i = i + 1 - end - end - return false - end - - --- Registers an event handler. - -- @tparam function f function handling event - -- @treturn number id of the event handler - function mist.addEventHandler(f) --id is optional! - local handler = {} - idNum = idNum + 1 - handler.id = idNum - handler.f = f - function handler:onEvent(event) - self.f(event) - end - world.addEventHandler(handler) - return handler.id - end - - --- Removes event handler with given id. - -- @tparam number id event handler id - -- @treturn boolean true on success, false otherwise - function mist.removeEventHandler(id) - for key, handler in pairs(world.eventHandlers) do - if handler.id and handler.id == id then - world.eventHandlers[key] = nil - return true - end - end - return false - end -end - --- Begin common funcs -do - --- Returns MGRS coordinates as string. - -- @tparam string MGRS MGRS coordinates - -- @tparam number acc the accuracy of each easting/northing. - -- Can be: 0, 1, 2, 3, 4, or 5. - function mist.tostringMGRS(MGRS, acc) - if acc == 0 then - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph - else - return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Easting/(10^(5-acc)), 0)) - .. ' ' .. string.format('%0' .. acc .. 'd', mist.utils.round(MGRS.Northing/(10^(5-acc)), 0)) - end - end - - --[[acc: - in DM: decimal point of minutes. - In DMS: decimal point of seconds. - position after the decimal of the least significant digit: - So: - 42.32 - acc of 2. - ]] - function mist.tostringLL(lat, lon, acc, DMS) - - local latHemi, lonHemi - if lat > 0 then - latHemi = 'N' - else - latHemi = 'S' - end - - if lon > 0 then - lonHemi = 'E' - else - lonHemi = 'W' - end - - lat = math.abs(lat) - lon = math.abs(lon) - - local latDeg = math.floor(lat) - local latMin = (lat - latDeg)*60 - - local lonDeg = math.floor(lon) - local lonMin = (lon - lonDeg)*60 - - if DMS then -- degrees, minutes, and seconds. - local oldLatMin = latMin - latMin = math.floor(latMin) - local latSec = mist.utils.round((oldLatMin - latMin)*60, acc) - - local oldLonMin = lonMin - lonMin = math.floor(lonMin) - local lonSec = mist.utils.round((oldLonMin - lonMin)*60, acc) - - if latSec == 60 then - latSec = 0 - latMin = latMin + 1 - end - - if lonSec == 60 then - lonSec = 0 - lonMin = lonMin + 1 - end - - local secFrmtStr -- create the formatting string for the seconds place - if acc <= 0 then -- no decimal place. - secFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - secFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi - - else -- degrees, decimal minutes. - latMin = mist.utils.round(latMin, acc) - lonMin = mist.utils.round(lonMin, acc) - - if latMin == 60 then - latMin = 0 - latDeg = latDeg + 1 - end - - if lonMin == 60 then - lonMin = 0 - lonDeg = lonDeg + 1 - end - - local minFrmtStr -- create the formatting string for the minutes place - if acc <= 0 then -- no decimal place. - minFrmtStr = '%02d' - else - local width = 3 + acc -- 01.310 - that's a width of 6, for example. - minFrmtStr = '%0' .. width .. '.' .. acc .. 'f' - end - - return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' ' - .. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi - - end - end - - --[[ required: az - radian - required: dist - meters - optional: alt - meters (set to false or nil if you don't want to use it). - optional: metric - set true to get dist and alt in km and m. - precision will always be nearest degree and NM or km.]] - function mist.tostringBR(az, dist, alt, metric) - az = mist.utils.round(mist.utils.toDegree(az), 0) - - if metric then - dist = mist.utils.round(dist/1000, 0) - else - dist = mist.utils.round(mist.utils.metersToNM(dist), 0) - end - - local s = string.format('%03d', az) .. ' for ' .. dist - - if alt then - if metric then - s = s .. ' at ' .. mist.utils.round(alt, 0) - else - s = s .. ' at ' .. mist.utils.round(mist.utils.metersToFeet(alt), 0) - end - end - return s - end - - function mist.getNorthCorrection(gPoint) --gets the correction needed for true north - local point = mist.utils.deepCopy(gPoint) - if not point.z then --Vec2; convert to Vec3 - point.z = point.y - point.y = 0 - end - local lat, lon = coord.LOtoLL(point) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2(north_posit.z - point.z, north_posit.x - point.x) - end - - --- Returns skill of the given unit. - -- @tparam string unitName unit name - -- @return skill of the unit - function mist.getUnitSkill(unitName) - if mist.DBs.unitsByName[unitName] then - if Unit.getByName(unitName) then - local lunit = Unit.getByName(unitName) - local data = mist.DBs.unitsByName[unitName] - if data.unitName == unitName and data.type == lunit:getTypeName() and data.unitId == tonumber(lunit:getID()) and data.skill then - return data.skill - end - end - end - log:error("Unit not found in DB: $1", unitName) - return false - end - - --- Returns an array containing a group's units positions. - -- e.g. - -- { - -- [1] = {x = 299435.224, y = -1146632.6773}, - -- [2] = {x = 663324.6563, y = 322424.1112} - -- } - -- @tparam number|string groupIdent group id or name - -- @treturn table array containing positions of each group member - function mist.getGroupPoints(groupIdent) - -- search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - if mist.DBs.MEgroupsByName[groupIdent] then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - else - log:error("Group not found in mist.DBs.MEgroupsByName: $1", groupIdent) - end - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" then -- only these types have points - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - for point_num, point in pairs(group_data.route.points) do - if not point.point then - points[point_num] = { x = point.x, y = point.y } - else - points[point_num] = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - end - return points - end - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_cat_data.group) do - end --if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then - end --if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" or obj_cat_name == "static" then - end --for obj_cat_name, obj_cat_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - end - - --- getUnitAttitude(unit) return values. - -- Yaw, AoA, ClimbAngle - relative to earth reference - -- DOES NOT TAKE INTO ACCOUNT WIND. - -- @table attitude - -- @tfield number Heading in radians, range of 0 to 2*pi, - -- relative to true north. - -- @tfield number Pitch in radians, range of -pi/2 to pi/2 - -- @tfield number Roll in radians, range of 0 to 2*pi, - -- right roll is positive direction. - -- @tfield number Yaw in radians, range of -pi to pi, - -- right yaw is positive direction. - -- @tfield number AoA in radians, range of -pi to pi, - -- rotation of aircraft to the right in comparison to - -- flight direction being positive. - -- @tfield number ClimbAngle in radians, range of -pi/2 to pi/2 - - --- Returns the attitude of a given unit. - -- Will work on any unit, even if not an aircraft. - -- @tparam Unit unit unit whose attitude is returned. - -- @treturn table @{attitude} - function mist.getAttitude(unit) - local unitpos = unit:getPosition() - if unitpos then - - local Heading = math.atan2(unitpos.x.z, unitpos.x.x) - - Heading = Heading + mist.getNorthCorrection(unitpos.p) - - if Heading < 0 then - Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi - end - ---- heading complete.---- - - local Pitch = math.asin(unitpos.x.y) - ---- pitch complete.---- - - -- now get roll: - --maybe not the best way to do it, but it works. - - --first, make a vector that is perpendicular to y and unitpos.x with cross product - local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) - - --now, get dot product of of this cross product with unitpos.z - local dp = mist.vec.dp(cp, unitpos.z) - - --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) - local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) - - --now, have to get sign of roll. - -- by convention, making right roll positive - -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. - - if unitpos.z.y > 0 then -- left roll, flip the sign of the roll - Roll = -Roll - end - ---- roll complete. ---- - - --now, work on yaw, AoA, climb, and abs velocity - local Yaw - local AoA - local ClimbAngle - - -- get unit velocity - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - --Yaw is the angle between unitpos.x and the x and z velocities - --define right yaw as positive - Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) - - --now set correct direction: - if AxialVel.z > 0 then - Yaw = -Yaw - end - - -- AoA is angle between unitpos.x and the x and y velocities - AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) - - --now set correct direction: - if AxialVel.y > 0 then - AoA = -AoA - end - - ClimbAngle = math.asin(unitvel.y/mist.vec.mag(unitvel)) - end - return { Heading = Heading, Pitch = Pitch, Roll = Roll, Yaw = Yaw, AoA = AoA, ClimbAngle = ClimbAngle} - else - log:error("Couldn't get unit's position") - end - end - - --- Returns heading of given unit. - -- @tparam Unit unit unit whose heading is returned. - -- @param rawHeading - -- @treturn number heading of the unit, in range - -- of 0 to 2*pi. - function mist.getHeading(unit, rawHeading) - local unitpos = unit:getPosition() - if unitpos then - local Heading = math.atan2(unitpos.x.z, unitpos.x.x) - if not rawHeading then - Heading = Heading + mist.getNorthCorrection(unitpos.p) - end - if Heading < 0 then - Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi - end - return Heading - end - end - - --- Returns given unit's pitch - -- @tparam Unit unit unit whose pitch is returned. - -- @treturn number pitch of given unit - function mist.getPitch(unit) - local unitpos = unit:getPosition() - if unitpos then - return math.asin(unitpos.x.y) - end - end - - --- Returns given unit's roll. - -- @tparam Unit unit unit whose roll is returned. - -- @treturn number roll of given unit - function mist.getRoll(unit) - local unitpos = unit:getPosition() - if unitpos then - -- now get roll: - --maybe not the best way to do it, but it works. - - --first, make a vector that is perpendicular to y and unitpos.x with cross product - local cp = mist.vec.cp(unitpos.x, {x = 0, y = 1, z = 0}) - - --now, get dot product of of this cross product with unitpos.z - local dp = mist.vec.dp(cp, unitpos.z) - - --now get the magnitude of the roll (magnitude of the angle between two vectors is acos(vec1.vec2/|vec1||vec2|) - local Roll = math.acos(dp/(mist.vec.mag(cp)*mist.vec.mag(unitpos.z))) - - --now, have to get sign of roll. - -- by convention, making right roll positive - -- to get sign of roll, use the y component of unitpos.z. For right roll, y component is negative. - - if unitpos.z.y > 0 then -- left roll, flip the sign of the roll - Roll = -Roll - end - return Roll - end - end - - --- Returns given unit's yaw. - -- @tparam Unit unit unit whose yaw is returned. - -- @treturn number yaw of given unit. - function mist.getYaw(unit) - local unitpos = unit:getPosition() - if unitpos then - -- get unit velocity - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - --Yaw is the angle between unitpos.x and the x and z velocities - --define right yaw as positive - local Yaw = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = 0, z = AxialVel.z})/mist.vec.mag({x = AxialVel.x, y = 0, z = AxialVel.z})) - - --now set correct direction: - if AxialVel.z > 0 then - Yaw = -Yaw - end - return Yaw - end - end - end - - --- Returns given unit's angle of attack. - -- @tparam Unit unit unit to get AoA from. - -- @treturn number angle of attack of the given unit. - function mist.getAoA(unit) - local unitpos = unit:getPosition() - if unitpos then - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - local AxialVel = {} --unit velocity transformed into aircraft axes directions - - --transform velocity components in direction of aircraft axes. - AxialVel.x = mist.vec.dp(unitpos.x, unitvel) - AxialVel.y = mist.vec.dp(unitpos.y, unitvel) - AxialVel.z = mist.vec.dp(unitpos.z, unitvel) - - -- AoA is angle between unitpos.x and the x and y velocities - local AoA = math.acos(mist.vec.dp({x = 1, y = 0, z = 0}, {x = AxialVel.x, y = AxialVel.y, z = 0})/mist.vec.mag({x = AxialVel.x, y = AxialVel.y, z = 0})) - - --now set correct direction: - if AxialVel.y > 0 then - AoA = -AoA - end - return AoA - end - end - end - - --- Returns given unit's climb angle. - -- @tparam Unit unit unit to get climb angle from. - -- @treturn number climb angle of given unit. - function mist.getClimbAngle(unit) - local unitpos = unit:getPosition() - if unitpos then - local unitvel = unit:getVelocity() - if mist.vec.mag(unitvel) ~= 0 then --must have non-zero velocity! - return math.asin(unitvel.y/mist.vec.mag(unitvel)) - end - end - end - - --[[-- - Unit name table. - Many Mist functions require tables of unit names, which are known - in Mist as UnitNameTables. These follow a special set of shortcuts - borrowed from Slmod. These shortcuts alleviate the problem of entering - huge lists of unit names by hand, and in many cases, they remove the - need to even know the names of the units in the first place! - - These are the unit table "short-cut" commands: - - Prefixes: - "[-u]" - subtract this unit if its in the table - "[g]" - add this group to the table - "[-g]" - subtract this group from the table - "[c]" - add this country's units - "[-c]" - subtract this country's units if any are in the table - - Stand-alone identifiers - "[all]" - add all units - "[-all]" - subtract all units (not very useful by itself) - "[blue]" - add all blue units - "[-blue]" - subtract all blue units - "[red]" - add all red coalition units - "[-red]" - subtract all red units - - Compound Identifiers: - "[c][helicopter]" - add all of this country's helicopters - "[-c][helicopter]" - subtract all of this country's helicopters - "[c][plane]" - add all of this country's planes - "[-c][plane]" - subtract all of this country's planes - "[c][ship]" - add all of this country's ships - "[-c][ship]" - subtract all of this country's ships - "[c][vehicle]" - add all of this country's vehicles - "[-c][vehicle]" - subtract all of this country's vehicles - - "[all][helicopter]" - add all helicopters - "[-all][helicopter]" - subtract all helicopters - "[all][plane]" - add all planes - "[-all][plane]" - subtract all planes - "[all][ship]" - add all ships - "[-all][ship]" - subtract all ships - "[all][vehicle]" - add all vehicles - "[-all][vehicle]" - subtract all vehicles - - "[blue][helicopter]" - add all blue coalition helicopters - "[-blue][helicopter]" - subtract all blue coalition helicopters - "[blue][plane]" - add all blue coalition planes - "[-blue][plane]" - subtract all blue coalition planes - "[blue][ship]" - add all blue coalition ships - "[-blue][ship]" - subtract all blue coalition ships - "[blue][vehicle]" - add all blue coalition vehicles - "[-blue][vehicle]" - subtract all blue coalition vehicles - - "[red][helicopter]" - add all red coalition helicopters - "[-red][helicopter]" - subtract all red coalition helicopters - "[red][plane]" - add all red coalition planes - "[-red][plane]" - subtract all red coalition planes - "[red][ship]" - add all red coalition ships - "[-red][ship]" - subtract all red coalition ships - "[red][vehicle]" - add all red coalition vehicles - "[-red][vehicle]" - subtract all red coalition vehicles - - Country names to be used in [c] and [-c] short-cuts: - Turkey - Norway - The Netherlands - Spain - 11 - UK - Denmark - USA - Georgia - Germany - Belgium - Canada - France - Israel - Ukraine - Russia - South Ossetia - Abkhazia - Italy - Australia - Austria - Belarus - Bulgaria - Czech Republic - China - Croatia - Finland - Greece - Hungary - India - Iran - Iraq - Japan - Kazakhstan - North Korea - Pakistan - Poland - Romania - Saudi Arabia - Serbia, Slovakia - South Korea - Sweden - Switzerland - Syria - USAF Aggressors - - Do NOT use a '[u]' notation for single units. Single units are referenced - the same way as before: Simply input their names as strings. - - These unit tables are evaluated in order, and you cannot subtract a unit - from a table before it is added. For example: - - {'[blue]', '[-c]Georgia'} - - will evaluate to all of blue coalition except those units owned by the - country named "Georgia"; however: - - {'[-c]Georgia', '[blue]'} - - will evaluate to all of the units in blue coalition, because the addition - of all units owned by blue coalition occurred AFTER the subtraction of all - units owned by Georgia (which actually subtracted nothing at all, since - there were no units in the table when the subtraction occurred). - - More examples: - - {'[blue][plane]', '[-c]Georgia', '[-g]Hawg 1'} - - Evaluates to all blue planes, except those blue units owned by the country - named "Georgia" and the units in the group named "Hawg1". - - - {'[g]arty1', '[g]arty2', '[-u]arty1_AD', '[-u]arty2_AD', 'Shark 11' } - - Evaluates to the unit named "Shark 11", plus all the units in groups named - "arty1" and "arty2" except those that are named "arty1\_AD" and "arty2\_AD". - - @table UnitNameTable - ]] - - --- Returns a table containing unit names. - -- @tparam table tbl sequential strings - -- @treturn table @{UnitNameTable} - function mist.makeUnitTable(tbl, exclude) - --Assumption: will be passed a table of strings, sequential - --log:info(tbl) - - - local excludeType = {} - if exclude then - if type(exclude) == 'table' then - for x, y in pairs(exclude) do - excludeType[x] = true - excludeType[y] = true - end - else - excludeType[exclude] = true - end - - end - - - local units_by_name = {} - - local l_munits = mist.DBs.units --local reference for faster execution - for i = 1, #tbl do - local unit = tbl[i] - if unit:sub(1,4) == '[-u]' then --subtract a unit - if units_by_name[unit:sub(5)] then -- 5 to end - units_by_name[unit:sub(5)] = nil --remove - end - elseif unit:sub(1,3) == '[g]' then -- add a group - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(4) then - -- index 4 to end - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - elseif unit:sub(1,4) == '[-g]' then -- subtract a group - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' and group_tbl.groupName == unit:sub(5) then - -- index 5 to end - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - elseif unit:sub(1,3) == '[c]' then -- add a country - local category = '' - local country_start = 4 - if unit:sub(4,15) == '[helicopter]' then - category = 'helicopter' - country_start = 16 - elseif unit:sub(4,10) == '[plane]' then - category = 'plane' - country_start = 11 - elseif unit:sub(4,9) == '[ship]' then - category = 'ship' - country_start = 10 - elseif unit:sub(4,12) == '[vehicle]' then - category = 'vehicle' - country_start = 13 - elseif unit:sub(4, 11) == '[static]' then - category = 'static' - country_start = 12 - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - if country == string.lower(unit:sub(country_start)) then -- match - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,4) == '[-c]' then -- subtract a country - local category = '' - local country_start = 5 - if unit:sub(5,16) == '[helicopter]' then - category = 'helicopter' - country_start = 17 - elseif unit:sub(5,11) == '[plane]' then - category = 'plane' - country_start = 12 - elseif unit:sub(5,10) == '[ship]' then - category = 'ship' - country_start = 11 - elseif unit:sub(5,13) == '[vehicle]' then - category = 'vehicle' - country_start = 14 - elseif unit:sub(5, 12) == '[static]' then - category = 'static' - country_start = 13 - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - if country == string.lower(unit:sub(country_start)) then -- match - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[blue]' then -- add blue coalition - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(7) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'blue' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,7) == '[-blue]' then -- subtract blue coalition - local category = '' - if unit:sub(8) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(8) == '[plane]' then - category = 'plane' - elseif unit:sub(8) == '[ship]' then - category = 'ship' - elseif unit:sub(8) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(8) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'blue' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,5) == '[red]' then -- add red coalition - local category = '' - if unit:sub(6) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(6) == '[plane]' then - category = 'plane' - elseif unit:sub(6) == '[ship]' then - category = 'ship' - elseif unit:sub(6) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(6) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'red' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[-red]' then -- subtract red coalition - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(7) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - if coa == 'red' then - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - end - elseif unit:sub(1,5) == '[all]' then -- add all of a certain category (or all categories) - local category = '' - if unit:sub(6) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(6) == '[plane]' then - category = 'plane' - elseif unit:sub(6) == '[ship]' then - category = 'ship' - elseif unit:sub(6) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(6) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - units_by_name[unit.unitName] = true --add - end - end - end - end - end - end - end - elseif unit:sub(1,6) == '[-all]' then -- subtract all of a certain category (or all categories) - local category = '' - if unit:sub(7) == '[helicopter]' then - category = 'helicopter' - elseif unit:sub(7) == '[plane]' then - category = 'plane' - elseif unit:sub(7) == '[ship]' then - category = 'ship' - elseif unit:sub(7) == '[vehicle]' then - category = 'vehicle' - elseif unit:sub(7) == '[static]' then - category = 'static' - end - for coa, coa_tbl in pairs(l_munits) do - for country, country_table in pairs(coa_tbl) do - for unit_type, unit_type_tbl in pairs(country_table) do - if type(unit_type_tbl) == 'table' and (category == '' or unit_type == category) and not excludeType[unit_type] then - for group_ind, group_tbl in pairs(unit_type_tbl) do - if type(group_tbl) == 'table' then - for unit_ind, unit in pairs(group_tbl.units) do - if units_by_name[unit.unitName] then - units_by_name[unit.unitName] = nil --remove - end - end - end - end - end - end - end - end - else -- just a regular unit - units_by_name[unit] = true --add - end - end - - local units_tbl = {} -- indexed sequentially - for unit_name, val in pairs(units_by_name) do - if val then - units_tbl[#units_tbl + 1] = unit_name -- add all the units to the table - end - end - - - units_tbl.processed = timer.getTime() --add the processed flag - return units_tbl -end - -function mist.getUnitsByAttribute(att, rnum, id) - local cEntry = {} - cEntry.typeName = att.type or att.typeName or att.typename - cEntry.country = att.country - cEntry.coalition = att.coalition - cEntry.skill = att.skill - cEntry.categry = att.category - - local num = rnum or 1 - - if cEntry.skill == 'human' then - cEntry.skill = {'Client', 'Player'} - end - - - local checkedVal = {} - local units = {} - for uName, uData in pairs(mist.DBs.unitsByName) do - local matched = 0 - for cName, cVal in pairs(cEntry) do - if type(cVal) == 'table' then - for sName, sVal in pairs(cVal) do - if (uData[cName] and uData[cName] == sVal) or (uData[cName] and uData[cName] == sName) then - matched = matched + 1 - end - end - else - if uData[cName] and uData[cName] == cVal then - matched = matched + 1 - end - end - end - if matched >= num then - if id then - units[uData.unitId] = true - else - - units[uName] = true - end - end - end - - local rtn = {} - for name, _ in pairs(units) do - table.insert(rtn, name) - end - return rtn - -end - -function mist.getGroupsByAttribute(att, rnum, id) - local cEntry = {} - cEntry.typeName = att.type or att.typeName or att.typename - cEntry.country = att.country - cEntry.coalition = att.coalition - cEntry.skill = att.skill - cEntry.categry = att.category - - local num = rnum or 1 - - if cEntry.skill == 'human' then - cEntry.skill = {'Client', 'Player'} - end - local groups = {} - for gName, gData in pairs(mist.DBs.groupsByName) do - local matched = 0 - for cName, cVal in pairs(cEntry) do - if type(cVal) == 'table' then - for sName, sVal in pairs(cVal) do - if cName == 'skill' or cName == 'typeName' then - local lMatch = 0 - for uId, uData in pairs(gData.units) do - if (uData[cName] and uData[cName] == sVal) or (gData[cName] and gData[cName] == sName) then - lMatch = lMatch + 1 - break - end - end - if lMatch > 0 then - matched = matched + 1 - end - end - if (gData[cName] and gData[cName] == sVal) or (gData[cName] and gData[cName] == sName) then - matched = matched + 1 - break - end - end - else - if cName == 'skill' or cName == 'typeName' then - local lMatch = 0 - for uId, uData in pairs(gData.units) do - if (uData[cName] and uData[cName] == sVal) then - lMatch = lMatch + 1 - break - end - end - if lMatch > 0 then - matched = matched + 1 - end - end - if gData[cName] and gData[cName] == cVal then - matched = matched + 1 - end - end - end - if matched >= num then - if id then - groups[gData.groupid] = true - else - groups[gName] = true - end - end - end - local rtn = {} - for name, _ in pairs(groups) do - table.insert(rtn, name) - end - return rtn - -end - -function mist.getDeadMapObjsInZones(zone_names) - -- zone_names: table of zone names - -- returns: table of dead map objects (indexed numerically) - local map_objs = {} - local zones = {} - for i = 1, #zone_names do - if mist.DBs.zonesByName[zone_names[i]] then - zones[#zones + 1] = mist.DBs.zonesByName[zone_names[i]] - end - end - for obj_id, obj in pairs(mist.DBs.deadObjects) do - if obj.objectType and obj.objectType == 'building' then --dead map object - for i = 1, #zones do - if ((zones[i].point.x - obj.objectPos.x)^2 + (zones[i].point.z - obj.objectPos.z)^2)^0.5 <= zones[i].radius then - map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) - end - end - end - end - return map_objs -end - -function mist.getDeadMapObjsInPolygonZone(zone) - -- zone_names: table of zone names - -- returns: table of dead map objects (indexed numerically) - local map_objs = {} - for obj_id, obj in pairs(mist.DBs.deadObjects) do - if obj.objectType and obj.objectType == 'building' then --dead map object - if mist.pointInPolygon(obj.objectPos, zone) then - map_objs[#map_objs + 1] = mist.utils.deepCopy(obj) - end - end - end - return map_objs -end -mist.shape = {} -function mist.shape.insideShape(shape1, shape2, full) - if shape1.radius then -- probably a circle - if shape2.radius then - return mist.shape.circleInCircle(shape1, shape2, full) - elseif shape2[1] then - return mist.shape.circleInPoly(shape1, shape2, full) - end - - elseif shape1[1] then -- shape1 is probably a polygon - if shape2.radius then - return mist.shape.polyInCircle(shape1, shape2, full) - elseif shape2[1] then - return mist.shape.polyInPoly(shape1, shape2, full) - end - end - return false -end - -function mist.shape.circleInCircle(c1, c2, full) - if not full then -- quick partial check - if mist.utils.get2DDist(c1.point, c2.point) <= c2.radius then - return true - end - end - local theta = mist.utils.getHeadingPoints(c2.point, c1.point) -- heading from - if full then - return mist.utils.get2DDist(mist.projectPoint(c1.point, c1.radius, theta), c2.point) <= c2.radius - else - return mist.utils.get2DDist(mist.projectPoint(c1.point, c1.radius, theta + math.pi), c2.point) <= c2.radius - end - return false -end - - -function mist.shape.circleInPoly(circle, poly, full) - - if poly and type(poly) == 'table' and circle and type(circle) == 'table' and circle.radius and circle.point then - if not full then - for i = 1, #poly do - if mist.utils.get2DDist(circle.point, poly[i]) <= circle.radius then - return true - end - end - end - -- no point is inside of the zone, now check if any part is - local count = 0 - for i = 1, #poly do - local theta -- heading of each set of points - if i == #poly then - theta = mist.utils.getHeadingPoints(poly[i],poly[1]) - else - theta = mist.utils.getHeadingPoints(poly[i],poly[i+1]) - end - -- offset - local pPoint = mist.projectPoint(circle.point, circle.radius, theta - (math.pi/180)) - local oPoint = mist.projectPoint(circle.point, circle.radius, theta + (math.pi/180)) - - - if mist.pointInPolygon(pPoint, poly) == true then - if (full and mist.pointInPolygon(oPoint, poly) == true) or not full then - return true - - end - - end - end - - end - return false -end - - -function mist.shape.polyInPoly(p1, p2, full) - local count = 0 - for i = 1, #p1 do - - if mist.pointInPolygon(p1[i], p2) then - count = count + 1 - end - if (not full) and count > 0 then - return true - end - end - if count == #p1 then - return true - end - - return false -end - -function mist.shape.polyInCircle(poly, circle, full) - local count = 0 - for i = 1, #poly do - if mist.utils.get2DDist(circle.point, poly[i]) <= circle.radius then - if full then - count = count + 1 - else - return true - end - end - end - if count == #poly then - return true - end - - return false -end - -function mist.shape.getPointOnSegment(point, seg, isSeg) - local p = mist.utils.makeVec2(point) - local s1 = mist.utils.makeVec2(seg[1]) - local s2 = mist.utils.makeVec2(seg[2]) - - - local cx, cy = p.x - s1.x, p.y - s1.y - local dx, dy = s2.x - s1.x, s2.x - s1.y - local d = (dx*dx + dy*dy) - - if d == 0 then - return {x = s1.x, y = s1.y} - end - local u = (cx*dx + cy*dy)/d - if isSeg then - if u < 0 then - u = 0 - elseif u > 1 then - u = 1 - end - end - return {x = s1.x + u*dx, y = s1.y + u*dy} -end - - -function mist.shape.segmentIntersect(segA, segB) - local dx1, dy1 = segA[2].x - segA[1].x, segA[2] - segA[1].y - local dx2, dy2 = segB[2].x - segB[1].x, segB[2] - segB[1].y - local dx3, dy3 = segA[1].x - segB[1].x, segA[1].y - segB[1].y - local d = dx1*dy2 - dy1*dx2 - if d == 0 then - return false - end - local t1 = (dx2*dy3 - dy2*dx3)/d - if t1 < 0 or t1 > 1 then - return false - end - local t2 = (dx1*dy3 - dy1*dx3)/d - if t2 < 0 or t2 > 1 then - return false - end - -- point of intersection - return true, segA[1].x + t1*dx1, segA[1].y + t1*dy1 -end - - -function mist.pointInPolygon(point, poly, maxalt) --raycasting point in polygon. Code from http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm - --[[local type_tbl = { - point = {'table'}, - poly = {'table'}, - maxalt = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.pointInPolygon', type_tbl, {point, poly, maxalt}) - assert(err, errmsg) - ]] - point = mist.utils.makeVec3(point) - local px = point.x - local pz = point.z - local cn = 0 - local newpoly = mist.utils.deepCopy(poly) - - if not maxalt or (point.y <= maxalt) then - local polysize = #newpoly - newpoly[#newpoly + 1] = newpoly[1] - - newpoly[1] = mist.utils.makeVec3(newpoly[1]) - - for k = 1, polysize do - newpoly[k+1] = mist.utils.makeVec3(newpoly[k+1]) - if ((newpoly[k].z <= pz) and (newpoly[k+1].z > pz)) or ((newpoly[k].z > pz) and (newpoly[k+1].z <= pz)) then - local vt = (pz - newpoly[k].z) / (newpoly[k+1].z - newpoly[k].z) - if (px < newpoly[k].x + vt*(newpoly[k+1].x - newpoly[k].x)) then - cn = cn + 1 - end - end - end - - return cn%2 == 1 - else - return false - end -end - -function mist.mapValue(val, inMin, inMax, outMin, outMax) - return (val - inMin) * (outMax - outMin) / (inMax - inMin) + outMin -end - -function mist.getUnitsInPolygon(unit_names, polyZone, max_alt) - local units = {} - - for i = 1, #unit_names do - units[#units + 1] = Unit.getByName(unit_names[i]) or StaticObject.getByName(unit_names[i]) - end - - local inZoneUnits = {} - for i =1, #units do - local lUnit = units[i] - local lCat = lUnit:getCategory() - if ((lCat == 1 and lUnit:isActive()) or lCat ~= 1) and mist.pointInPolygon(lUnit:getPosition().p, polyZone, max_alt) then - inZoneUnits[#inZoneUnits + 1] = lUnit - end - end - - return inZoneUnits -end - -function mist.getUnitsInZones(unit_names, zone_names, zone_type) - zone_type = zone_type or 'cylinder' - if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then - zone_type = 'cylinder' - end - if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then - zone_type = 'sphere' - end - - assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) - - local units = {} - local zones = {} - - if zone_names and type(zone_names) == 'string' then - zone_names = {zone_names} - end - for k = 1, #unit_names do - - local unit = Unit.getByName(unit_names[k]) or StaticObject.getByName(unit_names[k]) - if unit then - units[#units + 1] = unit - end - end - - - for k = 1, #zone_names do - local zone = mist.DBs.zonesByName[zone_names[k]] - if zone then - zones[#zones + 1] = {radius = zone.radius, x = zone.point.x, y = zone.point.y, z = zone.point.z, verts = zone.verticies} - end - end - - local in_zone_units = {} - for units_ind = 1, #units do - local lUnit = units[units_ind] - local unit_pos = lUnit:getPosition().p - local lCat = lUnit:getCategory() - for zones_ind = 1, #zones do - if zone_type == 'sphere' then --add land height value for sphere zone type - local alt = land.getHeight({x = zones[zones_ind].x, y = zones[zones_ind].z}) - if alt then - zones[zones_ind].y = alt - end - end - - if unit_pos and ((lCat == 1 and lUnit:isActive() == true) or lCat ~= 1) then -- it is a unit and is active or it is not a unit - if zones[zones_ind].verts then - if mist.pointInPolygon(unit_pos, zones[zones_ind].verts) then - in_zone_units[#in_zone_units + 1] = lUnit - end - - else - if zone_type == 'cylinder' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then - in_zone_units[#in_zone_units + 1] = lUnit - break - elseif zone_type == 'sphere' and (((unit_pos.x - zones[zones_ind].x)^2 + (unit_pos.y - zones[zones_ind].y)^2 + (unit_pos.z - zones[zones_ind].z)^2)^0.5 <= zones[zones_ind].radius) then - in_zone_units[#in_zone_units + 1] = lUnit - break - end - end - end - end - end - return in_zone_units -end - -function mist.getUnitsInMovingZones(unit_names, zone_unit_names, radius, zone_type) - - zone_type = zone_type or 'cylinder' - if zone_type == 'c' or zone_type == 'cylindrical' or zone_type == 'C' then - zone_type = 'cylinder' - end - if zone_type == 's' or zone_type == 'spherical' or zone_type == 'S' then - zone_type = 'sphere' - end - - assert(zone_type == 'cylinder' or zone_type == 'sphere', 'invalid zone_type: ' .. tostring(zone_type)) - - local units = {} - local zone_units = {} - - for k = 1, #unit_names do - local unit = Unit.getByName(unit_names[k]) or StaticObject.getByName(unit_names[k]) - if unit then - units[#units + 1] = unit - end - end - - for k = 1, #zone_unit_names do - local unit = Unit.getByName(zone_unit_names[k]) or StaticObject.getByName(zone_unit_names[k]) - if unit then - zone_units[#zone_units + 1] = unit - end - end - - local in_zone_units = {} - - for units_ind = 1, #units do - local lUnit = units[units_ind] - local lCat = lUnit:getCategory() - local unit_pos = lUnit:getPosition().p - for zone_units_ind = 1, #zone_units do - - local zone_unit_pos = zone_units[zone_units_ind]:getPosition().p - if unit_pos and zone_unit_pos and ((lCat == 1 and lUnit:isActive()) or lCat ~= 1) then - if zone_type == 'cylinder' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then - in_zone_units[#in_zone_units + 1] = lUnit - break - elseif zone_type == 'sphere' and (((unit_pos.x - zone_unit_pos.x)^2 + (unit_pos.y - zone_unit_pos.y)^2 + (unit_pos.z - zone_unit_pos.z)^2)^0.5 <= radius) then - in_zone_units[#in_zone_units + 1] = lUnit - break - end - end - end - end - return in_zone_units -end - -function mist.getUnitsLOS(unitset1, altoffset1, unitset2, altoffset2, radius) - log:info("$1, $2, $3, $4, $5", unitset1, altoffset1, unitset2, altoffset2, radius) - radius = radius or math.huge - local unit_info1 = {} - local unit_info2 = {} - - -- get the positions all in one step, saves execution time. - for unitset1_ind = 1, #unitset1 do - local unit1 = Unit.getByName(unitset1[unitset1_ind]) - local lCat = unit1:getCategory() - if unit1 and ((lCat == 1 and unit1:isActive()) or lCat ~= 1) then - unit_info1[#unit_info1 + 1] = {} - unit_info1[#unit_info1].unit = unit1 - unit_info1[#unit_info1].pos = unit1:getPosition().p - end - end - - for unitset2_ind = 1, #unitset2 do - local unit2 = Unit.getByName(unitset2[unitset2_ind]) - local lCat = unit2:getCategory() - if unit2 and ((lCat == 1 and unit2:isActive()) or lCat ~= 1) then - unit_info2[#unit_info2 + 1] = {} - unit_info2[#unit_info2].unit = unit2 - unit_info2[#unit_info2].pos = unit2:getPosition().p - end - end - - local LOS_data = {} - -- now compute los - for unit1_ind = 1, #unit_info1 do - local unit_added = false - for unit2_ind = 1, #unit_info2 do - if radius == math.huge or (mist.vec.mag(mist.vec.sub(unit_info1[unit1_ind].pos, unit_info2[unit2_ind].pos)) < radius) then -- inside radius - local point1 = { x = unit_info1[unit1_ind].pos.x, y = unit_info1[unit1_ind].pos.y + altoffset1, z = unit_info1[unit1_ind].pos.z} - local point2 = { x = unit_info2[unit2_ind].pos.x, y = unit_info2[unit2_ind].pos.y + altoffset2, z = unit_info2[unit2_ind].pos.z} - if land.isVisible(point1, point2) then - if unit_added == false then - unit_added = true - LOS_data[#LOS_data + 1] = {} - LOS_data[#LOS_data].unit = unit_info1[unit1_ind].unit - LOS_data[#LOS_data].vis = {} - LOS_data[#LOS_data].vis[#LOS_data[#LOS_data].vis + 1] = unit_info2[unit2_ind].unit - else - LOS_data[#LOS_data].vis[#LOS_data[#LOS_data].vis + 1] = unit_info2[unit2_ind].unit - end - end - end - end - end - - return LOS_data -end - -function mist.getAvgPoint(points) - local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 - for i = 1, #points do - --log:warn(points[i]) - local nPoint = mist.utils.makeVec3(points[i]) - if nPoint.z then - avgX = avgX + nPoint.x - avgY = avgY + nPoint.y - avgZ = avgZ + nPoint.z - totNum = totNum + 1 - end - end - if totNum ~= 0 then - return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} - end -end - ---Gets the average position of a group of units (by name) -function mist.getAvgPos(unitNames) - local avgX, avgY, avgZ, totNum = 0, 0, 0, 0 - for i = 1, #unitNames do - local unit - if Unit.getByName(unitNames[i]) then - unit = Unit.getByName(unitNames[i]) - elseif StaticObject.getByName(unitNames[i]) then - unit = StaticObject.getByName(unitNames[i]) - end - if unit then - local pos = unit:getPosition().p - if pos then -- you never know O.o - avgX = avgX + pos.x - avgY = avgY + pos.y - avgZ = avgZ + pos.z - totNum = totNum + 1 - end - end - end - if totNum ~= 0 then - return {x = avgX/totNum, y = avgY/totNum, z = avgZ/totNum} - end -end - -function mist.getAvgGroupPos(groupName) - if type(groupName) == 'string' and Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - groupName = Group.getByName(groupName) - end - local units = {} - for i = 1, groupName:getSize() do - table.insert(units, groupName:getUnit(i):getName()) - end - - return mist.getAvgPos(units) - -end - ---[[ vars for mist.getMGRSString: -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -]] -function mist.getMGRSString(vars) - local units = vars.units - local acc = vars.acc or 5 - local avgPos = mist.getAvgPos(units) - if avgPos then - return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(avgPos)), acc) - end -end - ---[[ vars for mist.getLLString -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. -]] -function mist.getLLString(vars) - local units = vars.units - local acc = vars.acc or 3 - local DMS = vars.DMS - local avgPos = mist.getAvgPos(units) - if avgPos then - local lat, lon = coord.LOtoLL(avgPos) - return mist.tostringLL(lat, lon, acc, DMS) - end -end - ---[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -]] -function mist.getBRString(vars) - local units = vars.units - local ref = mist.utils.makeVec3(vars.ref, 0) -- turn it into Vec3 if it is not already. - local alt = vars.alt - local metric = vars.metric - local avgPos = mist.getAvgPos(units) - if avgPos then - local vec = {x = avgPos.x - ref.x, y = avgPos.y - ref.y, z = avgPos.z - ref.z} - local dir = mist.utils.getDir(vec, ref) - local dist = mist.utils.get2DDist(avgPos, ref) - if alt then - alt = avgPos.y - end - return mist.tostringBR(dir, dist, alt, metric) - end -end - --- Returns the Vec3 coordinates of the average position of the concentration of units most in the heading direction. ---[[ vars for mist.getLeadingPos: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -]] -function mist.getLeadingPos(vars) - local units = vars.units - local heading = vars.heading - local radius = vars.radius - if vars.headingDegrees then - heading = mist.utils.toRadian(vars.headingDegrees) - end - - local unitPosTbl = {} - for i = 1, #units do - local unit = Unit.getByName(units[i]) - if unit and unit:isExist() then - unitPosTbl[#unitPosTbl + 1] = unit:getPosition().p - end - end - - if #unitPosTbl > 0 then -- one more more units found. - -- first, find the unit most in the heading direction - local maxPos = -math.huge - heading = heading * -1 -- rotated value appears to be opposite of what was expected - local maxPosInd -- maxPos - the furthest in direction defined by heading; maxPosInd = - for i = 1, #unitPosTbl do - local rotatedVec2 = mist.vec.rotateVec2(mist.utils.makeVec2(unitPosTbl[i]), heading) - if (not maxPos) or maxPos < rotatedVec2.x then - maxPos = rotatedVec2.x - maxPosInd = i - end - end - - --now, get all the units around this unit... - local avgPos - if radius then - local maxUnitPos = unitPosTbl[maxPosInd] - local avgx, avgy, avgz, totNum = 0, 0, 0, 0 - for i = 1, #unitPosTbl do - if mist.utils.get2DDist(maxUnitPos, unitPosTbl[i]) <= radius then - avgx = avgx + unitPosTbl[i].x - avgy = avgy + unitPosTbl[i].y - avgz = avgz + unitPosTbl[i].z - totNum = totNum + 1 - end - end - avgPos = { x = avgx/totNum, y = avgy/totNum, z = avgz/totNum} - else - avgPos = unitPosTbl[maxPosInd] - end - - return avgPos - end -end - ---[[ vars for mist.getLeadingMGRSString: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number, 0 to 5. -]] -function mist.getLeadingMGRSString(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local acc = vars.acc or 5 - return mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(pos)), acc) - end -end - ---[[ vars for mist.getLeadingLLString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. -]] -function mist.getLeadingLLString(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local acc = vars.acc or 3 - local DMS = vars.DMS - local lat, lon = coord.LOtoLL(pos) - return mist.tostringLL(lat, lon, acc, DMS) - end -end - ---[[ vars for mist.getLeadingBRString: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees -vars.metric - boolean, if true, use km instead of NM. -vars.alt - boolean, if true, include altitude. -vars.ref - vec3/vec2 reference point. -]] -function mist.getLeadingBRString(vars) - local pos = mist.getLeadingPos(vars) - if pos then - local ref = vars.ref - local alt = vars.alt - local metric = vars.metric - - local vec = {x = pos.x - ref.x, y = pos.y - ref.y, z = pos.z - ref.z} - local dir = mist.utils.getDir(vec, ref) - local dist = mist.utils.get2DDist(pos, ref) - if alt then - alt = pos.y - end - return mist.tostringBR(dir, dist, alt, metric) - end -end - ---[[getPathLength from GSH --- Returns the length between the defined set of points. Can also return the point index before the cutoff was achieved -p - table of path points, vec2 or vec3 -cutoff - number distance after which to stop at -topo - boolean for if it should get the topographical distance - -]] - -function mist.getPathLength(p, cutoff, topo) - local l = 0 - local cut = 0 or cutOff - local path = {} - - for i = 1, #p do - if topo then - table.insert(path, mist.utils.makeVec3GL(p[i])) - else - table.insert(path, mist.utils.makeVec3(p[i])) - end - end - - for i = 1, #path do - if i + 1 <= #path then - if topo then - l = mist.utils.get3DDist(path[i], path[i+1]) + l - else - l = mist.utils.get2DDist(path[i], path[i+1]) + l - end - end - if cut ~= 0 and l > cut then - return l, i - end - end - return l -end - ---[[ -Return a series of points to simplify the input table. Best used in conjunction with findPathOnRoads to turn the massive table into a list of X points. -p - table of path points, can be vec2 or vec3 -num - number of segments. -exact - boolean for whether or not it returns the exact distance or uses the first WP to that distance. - - -]] - -function mist.getPathInSegments(p, num, exact) - local tot = mist.getPathLength(p) - local checkDist = tot/num - local typeUsed = 'vec2' - - local points = {[1] = p[1]} - local curDist = 0 - for i = 1, #p do - if i + 1 <= #p then - curDist = mist.utils.get2DDist(p[i], p[i+1]) + curDist - if curDist > checkDist then - curDist = 0 - if exact then - -- get avg point between the two - -- insert into point table - -- need to be accurate... maybe reassign the point for the value it is checking? - -- insert into p table? - else - table.insert(points, p[i]) - end - end - - end - - end - return points - -end - - -function mist.getPointAtDistanceOnPath(p, dist, r, rtn) - log:info('find distance: $1', dist) - local rType = r or 'roads' - local point = {x= 0, y = 0, z = 0} - local path = {} - local ret = rtn or 'vec2' - local l = 0 - if p[1] and #p == 2 then - path = land.findPathOnRoads(rType, p[1].x, p[1].y, p[2].x, p[2].y) - else - path = p - end - for i = 1, #path do - if i + 1 <= #path then - nextPoint = path[i+1] - if topo then - l = mist.utils.get3DDist(path[i], path[i+1]) + l - else - l = mist.utils.get2DDist(path[i], path[i+1]) + l - end - end - if l > dist then - local diff = dist - if i ~= 1 then -- get difference - diff = l - dist - end - local dir = mist.utils.getHeadingPoints(mist.utils.makeVec3(path[i]), mist.utils.makeVec3(path[i+1])) - local x, y - if r then - x, y = land.getClosestPointOnRoads(rType, mist.utils.round((math.cos(dir) * diff) + path[i].x,1), mist.utils.round((math.sin(dir) * diff) + path[i].y,1)) - else - x, y = mist.utils.round((math.cos(dir) * diff) + path[i].x,1), mist.utils.round((math.sin(dir) * diff) + path[i].y,1) - end - - if ret == 'vec2' then - return {x = x, y = y}, dir - elseif ret == 'vec3' then - return {x = x, y = 0, z = y}, dir - end - - return {x = x, y = y}, dir - end - end - log:warn('Find point at distance: $1, path distance $2', dist, l) - return false -end - - -function mist.projectPoint(point, dist, theta) - local newPoint = {} - if point.z then - newPoint.z = mist.utils.round(math.sin(theta) * dist + point.z, 3) - newPoint.y = mist.utils.deepCopy(point.y) - else - newPoint.y = mist.utils.round(math.sin(theta) * dist + point.y, 3) - end - newPoint.x = mist.utils.round(math.cos(theta) * dist + point.x, 3) - - return newPoint -end - -end - - - - ---- Group functions. --- @section groups -do -- group functions scope - - --- Check table used for group creation. - -- @tparam table groupData table to check. - -- @treturn boolean true if a group can be spawned using - -- this table, false otherwise. - function mist.groupTableCheck(groupData) - -- return false if country, category - -- or units are missing - if not groupData.country or - not groupData.category or - not groupData.units then - return false - end - -- return false if unitData misses - -- x, y or type - for unitId, unitData in pairs(groupData.units) do - if not unitData.x or - not unitData.y or - not unitData.type then - return false - end - end - -- everything we need is here return true - return true - end - - --- Returns group data table of give group. - function mist.getCurrentGroupData(gpName) - local dbData = mist.getGroupData(gpName) - - if Group.getByName(gpName) and Group.getByName(gpName):isExist() == true then - local newGroup = Group.getByName(gpName) - local newData = {} - newData.name = gpName - newData.groupId = tonumber(newGroup:getID()) - newData.category = newGroup:getCategory() - newData.groupName = gpName - newData.hidden = dbData.hidden - - if newData.category == 2 then - newData.category = 'vehicle' - elseif newData.category == 3 then - newData.category = 'ship' - end - - newData.units = {} - local newUnits = newGroup:getUnits() - if #newUnits == 0 then - log:warn('getCurrentGroupData has returned no units for: $1', gpName) - end - for unitNum, unitData in pairs(newGroup:getUnits()) do - newData.units[unitNum] = {} - local uName = unitData:getName() - - if mist.DBs.unitsByName[uName] and unitData:getTypeName() == mist.DBs.unitsByName[uName].type and mist.DBs.unitsByName[uName].unitId == tonumber(unitData:getID()) then -- If old data matches most of new data - newData.units[unitNum] = mist.utils.deepCopy(mist.DBs.unitsByName[uName]) - else - newData.units[unitNum].unitId = tonumber(unitData:getID()) - newData.units[unitNum].type = unitData:getTypeName() - newData.units[unitNum].skill = mist.getUnitSkill(uName) - newData.country = string.lower(country.name[unitData:getCountry()]) - newData.units[unitNum].callsign = unitData:getCallsign() - newData.units[unitNum].unitName = uName - end - - newData.units[unitNum].x = unitData:getPosition().p.x - newData.units[unitNum].y = unitData:getPosition().p.z - newData.units[unitNum].point = {x = newData.units[unitNum].x, y = newData.units[unitNum].y} - newData.units[unitNum].heading = mist.getHeading(unitData, true) -- added to DBs - newData.units[unitNum].alt = unitData:getPosition().p.y - newData.units[unitNum].speed = mist.vec.mag(unitData:getVelocity()) - - end - - return newData - elseif StaticObject.getByName(gpName) and StaticObject.getByName(gpName):isExist() == true then - local staticObj = StaticObject.getByName(gpName) - dbData.units[1].x = staticObj:getPosition().p.x - dbData.units[1].y = staticObj:getPosition().p.z - dbData.units[1].alt = staticObj:getPosition().p.y - dbData.units[1].heading = mist.getHeading(staticObj, true) - - return dbData - end - - end - - function mist.getGroupData(gpName, route) - local found = false - local newData = {} - if mist.DBs.groupsByName[gpName] then - newData = mist.utils.deepCopy(mist.DBs.groupsByName[gpName]) - found = true - end - - if found == false then - for groupName, groupData in pairs(mist.DBs.groupsByName) do - if mist.stringMatch(groupName, gpName) == true then - newData = mist.utils.deepCopy(groupData) - newData.groupName = groupName - found = true - break - end - end - end - - local payloads - if newData.category == 'plane' or newData.category == 'helicopter' then - payloads = mist.getGroupPayload(newData.groupName) - end - if found == true then - --newData.hidden = false -- maybe add this to DBs - - for unitNum, unitData in pairs(newData.units) do - newData.units[unitNum] = {} - - newData.units[unitNum].unitId = unitData.unitId - --newData.units[unitNum].point = unitData.point - newData.units[unitNum].x = unitData.point.x - newData.units[unitNum].y = unitData.point.y - newData.units[unitNum].alt = unitData.alt - newData.units[unitNum].alt_type = unitData.alt_type - newData.units[unitNum].speed = unitData.speed - newData.units[unitNum].type = unitData.type - newData.units[unitNum].skill = unitData.skill - newData.units[unitNum].unitName = unitData.unitName - newData.units[unitNum].heading = unitData.heading -- added to DBs - newData.units[unitNum].playerCanDrive = unitData.playerCanDrive -- added to DBs - newData.units[unitNum].livery_id = unitData.livery_id - newData.units[unitNum].AddPropAircraft = unitData.AddPropAircraft - newData.units[unitNum].AddPropVehicle = unitData.AddPropVehicle - - - if newData.category == 'plane' or newData.category == 'helicopter' then - newData.units[unitNum].payload = payloads[unitNum] - - newData.units[unitNum].onboard_num = unitData.onboard_num - newData.units[unitNum].callsign = unitData.callsign - - end - if newData.category == 'static' then - newData.units[unitNum].categoryStatic = unitData.categoryStatic - newData.units[unitNum].mass = unitData.mass - newData.units[unitNum].canCargo = unitData.canCargo - newData.units[unitNum].shape_name = unitData.shape_name - end - end - --log:info(newData) - if route then - newData.route = mist.getGroupRoute(gpName, true) - end - - return newData - else - log:error('$1 not found in MIST database', gpName) - return - end - end - - function mist.getPayload(unitIdent) - -- refactor to search by groupId and allow groupId and groupName as inputs - local unitId = unitIdent - if type(unitIdent) == 'string' and not tonumber(unitIdent) then - if mist.DBs.MEunitsByName[unitIdent] then - unitId = mist.DBs.MEunitsByName[unitIdent].unitId - else - log:error("Unit not found in mist.DBs.MEunitsByName: $1", unitIdent) - end - end - local gpId = mist.DBs.MEunitsById[unitId].groupId - - if gpId and unitId then - for coa_name, coa_data in pairs(env.mission.coalition) do - if (coa_name == 'red' or coa_name == 'blue') and type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" then -- only these types have points - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.groupId == gpId then - for unitIndex, unitData in pairs(group_data.units) do --group index - if unitData.unitId == unitId then - return unitData.payload - end - end - end - end - end - end - end - end - end - end - end - else - log:error('Need string or number. Got: $1', type(unitIdent)) - return false - end - log:warn("Couldn't find payload for unit: $1", unitIdent) - return - end - - function mist.getGroupPayload(groupIdent) - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - if mist.DBs.MEgroupsByName[groupIdent] then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - else - log:error('$1 not found in mist.DBs.MEgroupsByName', groupIdent) - end - end - - if gpId then - for coa_name, coa_data in pairs(env.mission.coalition) do - if type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" then -- only these types have points - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.groupId == gpId then - local payloads = {} - for unitIndex, unitData in pairs(group_data.units) do --group index - payloads[unitIndex] = unitData.payload - end - return payloads - end - end - end - end - end - end - end - end - end - else - log:error('Need string or number. Got: $1', type(groupIdent)) - return false - end - log:warn("Couldn't find payload for group: $1", groupIdent) - return - end - - function mist.getGroupTable(groupIdent) - local gpId = groupIdent - if type(groupIdent) == 'string' and not tonumber(groupIdent) then - if mist.DBs.MEgroupsByName[groupIdent] then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - else - log:error('$1 not found in mist.DBs.MEgroupsByName', groupIdent) - end - end - - if gpId then - for coa_name, coa_data in pairs(env.mission.coalition) do - if type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" then -- only these types have points - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.groupId == gpId then - return group_data - end - end - end - end - end - end - end - end - end - else - log:error('Need string or number. Got: $1', type(groupIdent)) - return false - end - log:warn("Couldn't find table for group: $1", groupIdent) - - end - - function mist.getValidRandomPoint(vars) - - - end - - function mist.teleportToPoint(vars) -- main teleport function that all of teleport/respawn functions call - --log:warn(vars) - local point = vars.point - local gpName - if vars.gpName then - gpName = vars.gpName - elseif vars.groupName then - gpName = vars.groupName - else - log:error('Missing field groupName or gpName in variable table') - end - - --[[New vars to add, mostly for when called via inZone functions - anyTerrain - offsetWP1 - offsetRoute - initTasks - - ]] - - local action = vars.action - - local disperse = vars.disperse or false - local maxDisp = vars.maxDisp or 200 - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - - local dbData = false - - - - local newGroupData - if gpName and not vars.groupData then - if string.lower(action) == 'teleport' or string.lower(action) == 'tele' then - newGroupData = mist.getCurrentGroupData(gpName) - elseif string.lower(action) == 'respawn' then - newGroupData = mist.getGroupData(gpName) - dbData = true - elseif string.lower(action) == 'clone' then - newGroupData = mist.getGroupData(gpName) - newGroupData.clone = 'order66' - dbData = true - else - action = 'tele' - newGroupData = mist.getCurrentGroupData(gpName) - end - else - action = 'tele' - newGroupData = vars.groupData - end - - if vars.newGroupName then - newGroupData.groupName = vars.newGroupName - end - - if #newGroupData.units == 0 then - log:warn('$1 has no units in group table', gpName) - return - end - - --log:info('get Randomized Point') - local diff = {x = 0, y = 0} - local newCoord, origCoord - - local validTerrain = {'LAND', 'ROAD', 'SHALLOW_WATER', 'WATER', 'RUNWAY'} - if vars.anyTerrain then - -- do nothing - elseif vars.validTerrain then - validTerrain = vars.validTerrain - else - if string.lower(newGroupData.category) == 'ship' then - validTerrain = {'SHALLOW_WATER' , 'WATER'} - elseif string.lower(newGroupData.category) == 'vehicle' then - validTerrain = {'LAND', 'ROAD'} - end - end - - if point and radius >= 0 then - local valid = false - -- new thoughts - --[[ Get AVG position of group and max radius distance to that avg point, otherwise use disperse data to get zone area to check - if disperse then - - else - - end - -- ]] - - - - - - - ---- old - for i = 1, 100 do - newCoord = mist.getRandPointInCircle(point, radius, innerRadius) - if vars.anyTerrain or mist.isTerrainValid(newCoord, validTerrain) then - origCoord = mist.utils.deepCopy(newCoord) - diff = {x = (newCoord.x - newGroupData.units[1].x), y = (newCoord.y - newGroupData.units[1].y)} - valid = true - break - end - end - if valid == false then - log:error('Point supplied in variable table is not a valid coordinate. Valid coords: $1', validTerrain) - return false - end - end - if not newGroupData.country and mist.DBs.groupsByName[newGroupData.groupName].country then - newGroupData.country = mist.DBs.groupsByName[newGroupData.groupName].country - end - if not newGroupData.category and mist.DBs.groupsByName[newGroupData.groupName].category then - newGroupData.category = mist.DBs.groupsByName[newGroupData.groupName].category - end - --log:info(point) - for unitNum, unitData in pairs(newGroupData.units) do - --log:info(unitNum) - if disperse then - local unitCoord - if maxDisp and type(maxDisp) == 'number' and unitNum ~= 1 then - for i = 1, 100 do - unitCoord = mist.getRandPointInCircle(origCoord, maxDisp) - if mist.isTerrainValid(unitCoord, validTerrain) == true then - --log:warn('Index: $1, Itered: $2. AT: $3', unitNum, i, unitCoord) - break - end - end - - --else - --newCoord = mist.getRandPointInCircle(zone.point, zone.radius) - end - if unitNum == 1 then - unitCoord = mist.utils.deepCopy(newCoord) - end - if unitCoord then - newGroupData.units[unitNum].x = unitCoord.x - newGroupData.units[unitNum].y = unitCoord.y - end - else - newGroupData.units[unitNum].x = unitData.x + diff.x - newGroupData.units[unitNum].y = unitData.y + diff.y - end - if point then - if (newGroupData.category == 'plane' or newGroupData.category == 'helicopter') then - if point.z and point.y > 0 and point.y > land.getHeight({newGroupData.units[unitNum].x, newGroupData.units[unitNum].y}) + 10 then - newGroupData.units[unitNum].alt = point.y - --log:info('far enough from ground') - else - - if newGroupData.category == 'plane' then - --log:info('setNewAlt') - newGroupData.units[unitNum].alt = land.getHeight({newGroupData.units[unitNum].x, newGroupData.units[unitNum].y}) + math.random(300, 9000) - else - newGroupData.units[unitNum].alt = land.getHeight({newGroupData.units[unitNum].x, newGroupData.units[unitNum].y}) + math.random(200, 3000) - end - end - end - end - end - - if newGroupData.start_time then - newGroupData.startTime = newGroupData.start_time - end - - if newGroupData.startTime and newGroupData.startTime ~= 0 and dbData == true then - local timeDif = timer.getAbsTime() - timer.getTime0() - if timeDif > newGroupData.startTime then - newGroupData.startTime = 0 - else - newGroupData.startTime = newGroupData.startTime - timeDif - end - - end - - - local tempRoute - - if mist.DBs.MEgroupsByName[gpName] and not vars.route then - -- log:warn('getRoute') - tempRoute = mist.getGroupRoute(gpName, true) - elseif vars.route then - -- log:warn('routeExist') - tempRoute = mist.utils.deepCopy(vars.route) - end - -- log:warn(tempRoute) - if tempRoute then - if (vars.offsetRoute or vars.offsetWP1 or vars.initTasks) then - for i = 1, #tempRoute do - -- log:warn(i) - if (vars.offsetRoute) or (i == 1 and vars.offsetWP1) or (i == 1 and vars.initTasks) then - -- log:warn('update offset') - tempRoute[i].x = tempRoute[i].x + diff.x - tempRoute[i].y = tempRoute[i].y + diff.y - elseif vars.initTasks and i > 1 then - --log:warn('deleteWP') - tempRoute[i] = nil - end - end - end - newGroupData.route = tempRoute - end - - - --log:warn(newGroupData) - --mist.debug.writeData(mist.utils.serialize,{'teleportToPoint', newGroupData}, 'newGroupData.lua') - if string.lower(newGroupData.category) == 'static' then - --log:warn(newGroupData) - return mist.dynAddStatic(newGroupData) - end - return mist.dynAdd(newGroupData) - - end - - function mist.respawnInZone(gpName, zone, disperse, maxDisp, v) - - if type(gpName) == 'table' and gpName:getName() then - gpName = gpName:getName() - elseif type(gpName) == 'table' and gpName[1]:getName() then - gpName = math.random(#gpName) - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = mist.DBs.zonesByName[zone] - elseif type(zone) == 'table' and not zone.radius then - zone = mist.DBs.zonesByName[zone[math.random(1, #zone)]] - end - local vars = {} - vars.gpName = gpName - vars.action = 'respawn' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - - if v and type(v) == 'table' then - for index, val in pairs(v) do - vars[index] = val - end - end - - return mist.teleportToPoint(vars) - end - - function mist.cloneInZone(gpName, zone, disperse, maxDisp, v) - --log:info('cloneInZone') - if type(gpName) == 'table' then - gpName = gpName:getName() - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = mist.DBs.zonesByName[zone] - elseif type(zone) == 'table' and not zone.radius then - zone = mist.DBs.zonesByName[zone[math.random(1, #zone)]] - end - local vars = {} - vars.gpName = gpName - vars.action = 'clone' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - --log:info('do teleport') - if v and type(v) == 'table' then - for index, val in pairs(v) do - vars[index] = val - end - end - return mist.teleportToPoint(vars) - end - - function mist.teleportInZone(gpName, zone, disperse, maxDisp, v) -- groupName, zoneName or table of Zone Names, keepForm is a boolean - if type(gpName) == 'table' and gpName:getName() then - gpName = gpName:getName() - else - gpName = tostring(gpName) - end - - if type(zone) == 'string' then - zone = mist.DBs.zonesByName[zone] - elseif type(zone) == 'table' and not zone.radius then - zone = mist.DBs.zonesByName[zone[math.random(1, #zone)]] - end - - local vars = {} - vars.gpName = gpName - vars.action = 'tele' - vars.point = zone.point - vars.radius = zone.radius - vars.disperse = disperse - vars.maxDisp = maxDisp - if v and type(v) == 'table' then - for index, val in pairs(v) do - vars[index] = val - end - end - return mist.teleportToPoint(vars) - end - - function mist.respawnGroup(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'respawn' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup - end - - function mist.cloneGroup(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'clone' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup - end - - function mist.teleportGroup(gpName, task) - local vars = {} - vars.gpName = gpName - vars.action = 'teleport' - if task and type(task) ~= 'number' then - vars.route = mist.getGroupRoute(gpName, 'task') - end - local newGroup = mist.teleportToPoint(vars) - if task and type(task) == 'number' then - local newRoute = mist.getGroupRoute(gpName, 'task') - mist.scheduleFunction(mist.goRoute, {newGroup, newRoute}, timer.getTime() + task) - end - return newGroup - end - - function mist.spawnRandomizedGroup(groupName, vars) -- need to debug - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - local gpData = mist.getGroupData(groupName) - gpData.units = mist.randomizeGroupOrder(gpData.units, vars) - gpData.route = mist.getGroupRoute(groupName, 'task') - - mist.dynAdd(gpData) - end - - return true - end - - function mist.randomizeNumTable(vars) - local newTable = {} - - local excludeIndex = {} - local randomTable = {} - - if vars and vars.exclude and type(vars.exclude) == 'table' then - for index, data in pairs(vars.exclude) do - excludeIndex[data] = true - end - end - - local low, hi, size - - if vars.size then - size = vars.size - end - - if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then - low = mist.utils.round(vars.lowerLimit) - else - low = 1 - end - - if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then - hi = mist.utils.round(vars.upperLimit) - else - hi = size - end - - local choices = {} - -- add to exclude list and create list of what to randomize - for i = 1, size do - if not (i >= low and i <= hi) then - - excludeIndex[i] = true - end - if not excludeIndex[i] then - table.insert(choices, i) - else - newTable[i] = i - end - end - - for ind, num in pairs(choices) do - local found = false - local x = 0 - while found == false do - x = mist.random(size) -- get random number from list - local addNew = true - for index, _ in pairs(excludeIndex) do - if index == x then - addNew = false - break - end - end - if addNew == true then - excludeIndex[x] = true - found = true - end - excludeIndex[x] = true - - end - newTable[num] = x - end - --[[ - for i = 1, #newTable do - log:info(newTable[i]) - end - ]] - return newTable - end - - function mist.randomizeGroupOrder(passedUnits, vars) - -- figure out what to exclude, and send data to other func - local units = passedUnits - - if passedUnits.units then - units = passUnits.units - end - - local exclude = {} - local excludeNum = {} - if vars and vars.excludeType and type(vars.excludeType) == 'table' then - exclude = vars.excludeType - end - - if vars and vars.excludeNum and type(vars.excludeNum) == 'table' then - excludeNum = vars.excludeNum - end - - local low, hi - - if vars and vars.lowerLimit and type(vars.lowerLimit) == 'number' then - low = mist.utils.round(vars.lowerLimit) - else - low = 1 - end - - if vars and vars.upperLimit and type(vars.upperLimit) == 'number' then - hi = mist.utils.round(vars.upperLimit) - else - hi = #units - end - - - local excludeNum = {} - for unitIndex, unitData in pairs(units) do - if unitIndex >= low and unitIndex <= hi then -- if within range - local found = false - if #exclude > 0 then - for excludeType, index in pairs(exclude) do -- check if excluded - if mist.stringMatch(excludeType, unitData.type) then -- if excluded - excludeNum[unitIndex] = unitIndex - found = true - end - end - end - else -- unitIndex is either to low, or to high: added to exclude list - excludeNum[unitIndex] = unitId - end - end - - local newGroup = {} - local newOrder = mist.randomizeNumTable({exclude = excludeNum, size = #units}) - - for unitIndex, unitData in pairs(units) do - for i = 1, #newOrder do - if newOrder[i] == unitIndex then - newGroup[i] = mist.utils.deepCopy(units[i]) -- gets all of the unit data - newGroup[i].type = mist.utils.deepCopy(unitData.type) - newGroup[i].skill = mist.utils.deepCopy(unitData.skill) - newGroup[i].unitName = mist.utils.deepCopy(unitData.unitName) - newGroup[i].unitIndex = mist.utils.deepCopy(unitData.unitIndex) -- replaces the units data with a new type - end - end - end - return newGroup - end - - function mist.random(firstNum, secondNum) -- no support for decimals - local lowNum, highNum - if not secondNum then - highNum = firstNum - lowNum = 1 - else - lowNum = firstNum - highNum = secondNum - end - local total = 1 - if math.abs(highNum - lowNum + 1) < 50 then -- if total values is less than 50 - total = math.modf(50/math.abs(highNum - lowNum + 1)) -- make x copies required to be above 50 - end - local choices = {} - for i = 1, total do -- iterate required number of times - for x = lowNum, highNum do -- iterate between the range - choices[#choices +1] = x -- add each entry to a table - end - end - local rtnVal = math.random(#choices) -- will now do a math.random of at least 50 choices - for i = 1, 10 do - rtnVal = math.random(#choices) -- iterate a few times for giggles - end - return choices[rtnVal] - end - - function mist.stringCondense(s) - local exclude = {'%-', '%(', '%)', '%_', '%[', '%]', '%.', '%#', '% ', '%{', '%}', '%$', '%%', '%?', '%+', '%^'} - for i , str in pairs(exclude) do - s = string.gsub(s, str, '') - end - return s - end - - function mist.stringMatch(s1, s2, bool) - - if type(s1) == 'string' and type(s2) == 'string' then - s1 = mist.stringCondense(s1) - s2 = mist.stringCondense(s2) - if not bool then - s1 = string.lower(s1) - s2 = string.lower(s2) - end - --log:info('Comparing: $1 and $2', s1, s2) - if s1 == s2 then - return true - else - return false - end - else - log:error('Either the first or second variable were not a string') - return false - end - end - - mist.matchString = mist.stringMatch -- both commands work because order out type of I - - --[[ scope: -{ - units = {...}, -- unit names. - coa = {...}, -- coa names - countries = {...}, -- country names - CA = {...}, -- looks just like coa. - unitTypes = { red = {}, blue = {}, all = {}, Russia = {},} -} - - -scope examples: - -{ units = { 'Hawg11', 'Hawg12' }, CA = {'blue'} } - -{ countries = {'Georgia'}, unitTypes = {blue = {'A-10C', 'A-10A'}}} - -{ coa = {'all'}} - -{unitTypes = { blue = {'A-10C'}}} -]] -end - ---- Utility functions. --- E.g. conversions between units etc. --- @section mist.utils -do -- mist.util scope - mist.utils = {} - - --- Converts angle in radians to degrees. - -- @param angle angle in radians - -- @return angle in degrees - function mist.utils.toDegree(angle) - return angle*180/math.pi - end - - --- Converts angle in degrees to radians. - -- @param angle angle in degrees - -- @return angle in degrees - function mist.utils.toRadian(angle) - return angle*math.pi/180 - end - - --- Converts meters to nautical miles. - -- @param meters distance in meters - -- @return distance in nautical miles - function mist.utils.metersToNM(meters) - return meters/1852 - end - - --- Converts meters to feet. - -- @param meters distance in meters - -- @return distance in feet - function mist.utils.metersToFeet(meters) - return meters/0.3048 - end - - --- Converts nautical miles to meters. - -- @param nm distance in nautical miles - -- @return distance in meters - function mist.utils.NMToMeters(nm) - return nm*1852 - end - - --- Converts feet to meters. - -- @param feet distance in feet - -- @return distance in meters - function mist.utils.feetToMeters(feet) - return feet*0.3048 - end - - --- Converts meters per second to knots. - -- @param mps speed in m/s - -- @return speed in knots - function mist.utils.mpsToKnots(mps) - return mps*3600/1852 - end - - --- Converts meters per second to kilometers per hour. - -- @param mps speed in m/s - -- @return speed in km/h - function mist.utils.mpsToKmph(mps) - return mps*3.6 - end - - --- Converts knots to meters per second. - -- @param knots speed in knots - -- @return speed in m/s - function mist.utils.knotsToMps(knots) - return knots*1852/3600 - end - - --- Converts kilometers per hour to meters per second. - -- @param kmph speed in km/h - -- @return speed in m/s - function mist.utils.kmphToMps(kmph) - return kmph/3.6 - end - - function mist.utils.kelvinToCelsius(t) - return t - 273.15 - end - - function mist.utils.FahrenheitToCelsius(f) - return (f - 32) * (5/9) - end - - function mist.utils.celsiusToFahrenheit(c) - return c*(9/5)+32 - end - - function mist.utils.hexToRGB(hex, l) -- because for some reason the draw tools use hex when everything is rgba 0 - 1 - local int = 255 - if l then - int = 1 - end - if hex and type(hex) == 'string' then - local val = {} - hex = string.gsub(hex, '0x', '') - if string.len(hex) == 8 then - val[1] = tonumber("0x"..hex:sub(1,2)) / int - val[2] = tonumber("0x"..hex:sub(3,4)) / int - val[3] = tonumber("0x"..hex:sub(5,6)) / int - val[4] = tonumber("0x"..hex:sub(7,8)) / int - - return val - end - end - end - - function mist.utils.converter(t1, t2, val) - if type(t1) == 'string' then - t1 = string.lower(t1) - end - if type(t2) == 'string' then - t2 = string.lower(t2) - end - if val and type(val) ~= 'number' then - if tonumber(val) then - val = tonumber(val) - else - log:warn("Value given is not a number: $1", val) - return 0 - end - end - - -- speed - if t1 == 'mps' then - if t2 == 'kmph' then - return val * 3.6 - elseif t2 == 'knots' or t2 == 'knot' then - return val * 3600/1852 - end - elseif t1 == 'kmph' then - if t2 == 'mps' then - return val/3.6 - elseif t2 == 'knots' or t2 == 'knot' then - return val*0.539957 - end - elseif t1 == 'knot' or t1 == 'knots' then - if t2 == 'kmph' then - return val * 1.852 - elseif t2 == 'mps' then - return val * 0.514444 - end - - -- Distance - elseif t1 == 'feet' or t1 == 'ft' then - if t2 == 'nm' then - return val/6076.12 - elseif t2 == 'km' then - return (val*0.3048)/1000 - elseif t2 == 'm' then - return val*0.3048 - end - elseif t1 == 'nm' then - if t2 == 'feet' or t2 == 'ft' then - return val*6076.12 - elseif t2 == 'km' then - return val*1.852 - elseif t2 == 'm' then - return val*1852 - end - elseif t1 == 'km' then - if t2 == 'nm' then - return val/1.852 - elseif t2 == 'feet' or t2 == 'ft' then - return (val/0.3048)*1000 - elseif t2 == 'm' then - return val*1000 - end - elseif t1 == 'm' then - if t2 == 'nm' then - return val/1852 - elseif t2 == 'km' then - return val/1000 - elseif t2 == 'feet' or t2 == 'ft' then - return val/0.3048 - end - - -- Temperature - elseif t1 == 'f' or t1 == 'fahrenheit' then - if t2 == 'c' or t2 == 'celsius' then - return (val - 32) * (5/9) - elseif t2 == 'k' or t2 == 'kelvin' then - return (val + 459.67) * (5/9) - end - elseif t1 == 'c' or t1 == 'celsius' then - if t2 == 'f' or t2 == 'fahrenheit' then - return val*(9/5)+32 - elseif t2 == 'k' or t2 == 'kelvin' then - return val + 273.15 - end - elseif t1 == 'k' or t1 == 'kelvin' then - if t2 == 'c' or t2 == 'celsius' then - return val - 273.15 - elseif t2 == 'f' or t2 == 'fahrenheit' then - return ((val*(9/5))-459.67) - end - - -- Pressure - elseif t1 == 'p' or t1 == 'pascal' or t1 == 'pascals' then - if t2 == 'hpa' or t2 == 'hectopascal' then - return val/100 - elseif t2 == 'mmhg' then - return val * 0.00750061561303 - elseif t2 == 'inhg' then - return val * 0.0002953 - end - elseif t1 == 'hpa' or t1 == 'hectopascal' then - if t2 == 'p' or t2 == 'pascal' or t2 == 'pascals' then - return val*100 - elseif t2 == 'mmhg' then - return val * 0.00750061561303 - elseif t2 == 'inhg' then - return val * 0.02953 - end - elseif t1 == 'mmhg' then - if t2 == 'p' or t2 == 'pascal' or t2 == 'pascals' then - return val / 0.00750061561303 - elseif t2 == 'hpa' or t2 == 'hectopascal' then - return val * 1.33322 - elseif t2 == 'inhg' then - return val/25.4 - end - elseif t1 == 'inhg' then - if t2 == 'p' or t2 == 'pascal' or t2 == 'pascals' then - return val*3386.39 - elseif t2 == 'mmhg' then - return val*25.4 - elseif t2 == 'hpa' or t2 == 'hectopascal' then - return val * 33.8639 - end - else - log:warn("First value doesn't match with list. Value given: $1", t1) - end - log:warn("Match not found. Unable to convert: $1 into $2", t1, t2) - - end - - mist.converter = mist.utils.converter - - function mist.utils.getQFE(point, inchHg) - - local t, p = 0, 0 - if atmosphere.getTemperatureAndPressure then - t, p = atmosphere.getTemperatureAndPressure(mist.utils.makeVec3GL(point)) - end - if p == 0 then - local h = land.getHeight(mist.utils.makeVec2(point))/0.3048 -- convert to feet - if inchHg then - return (env.mission.weather.qnh - (h/30)) * 0.0295299830714 - else - return env.mission.weather.qnh - (h/30) - end - else - if inchHg then - return mist.converter('p', 'inhg', p) - else - return mist.converter('p', 'hpa', p) - end - end - - end - --- Converts a Vec3 to a Vec2. - -- @tparam Vec3 vec the 3D vector - -- @return vector converted to Vec2 - function mist.utils.makeVec2(vec) - if vec.z then - return {x = vec.x, y = vec.z} - else - return {x = vec.x, y = vec.y} -- it was actually already vec2. - end - end - - --- Converts a Vec2 to a Vec3. - -- @tparam Vec2 vec the 2D vector - -- @param y optional new y axis (altitude) value. If omitted it's 0. - function mist.utils.makeVec3(vec, y) - if not vec.z then - if vec.alt and not y then - y = vec.alt - elseif not y then - y = 0 - end - return {x = vec.x, y = y, z = vec.y} - else - return {x = vec.x, y = vec.y, z = vec.z} -- it was already Vec3, actually. - end - end - - --- Converts a Vec2 to a Vec3 using ground level as altitude. - -- The ground level at the specific point is used as altitude (y-axis) - -- for the new vector. Optionally a offset can be specified. - -- @tparam Vec2 vec the 2D vector - -- @param[opt] offset offset to be applied to the ground level - -- @return new 3D vector - function mist.utils.makeVec3GL(vec, offset) - local adj = offset or 0 - - if not vec.z then - return {x = vec.x, y = (land.getHeight(vec) + adj), z = vec.y} - else - return {x = vec.x, y = (land.getHeight({x = vec.x, y = vec.z}) + adj), z = vec.z} - end - end - - --- Returns the center of a zone as Vec3. - -- @tparam string|table zone trigger zone name or table - -- @treturn Vec3 center of the zone - function mist.utils.zoneToVec3(zone, gl) - local new = {} - if type(zone) == 'table' then - if zone.point then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - elseif zone.x and zone.y and zone.z then - new = mist.utils.deepCopy(zone) - end - return new - elseif type(zone) == 'string' then - zone = trigger.misc.getZone(zone) - if zone then - new.x = zone.point.x - new.y = zone.point.y - new.z = zone.point.z - end - end - if new.x and gl then - new.y = land.getHeight({x = new.x, y = new.z}) - end - return new - end - - function mist.utils.getHeadingPoints(point1, point2, north) -- sick of writing this out. - if north then - return mist.utils.getDir(mist.vec.sub(mist.utils.makeVec3(point2), mist.utils.makeVec3(point1)), (mist.utils.makeVec3(point1))) - else - return mist.utils.getDir(mist.vec.sub(mist.utils.makeVec3(point2), mist.utils.makeVec3(point1))) - end - end - --- Returns heading-error corrected direction. - -- True-north corrected direction from point along vector vec. - -- @tparam Vec3 vec - -- @tparam Vec2 point - -- @return heading-error corrected direction from point. - function mist.utils.getDir(vec, point) - local dir = math.atan2(vec.z, vec.x) - if point then - dir = dir + mist.getNorthCorrection(point) - end - if dir < 0 then - dir = dir + 2 * math.pi -- put dir in range of 0 to 2*pi - end - return dir - end - - --- Returns distance in meters between two points. - -- @tparam Vec2|Vec3 point1 first point - -- @tparam Vec2|Vec3 point2 second point - -- @treturn number distance between given points. - function mist.utils.get2DDist(point1, point2) - if not point1 then - log:warn("mist.utils.get2DDist 1st input value is nil") - end - if not point2 then - log:warn("mist.utils.get2DDist 2nd input value is nil") - end - point1 = mist.utils.makeVec3(point1) - point2 = mist.utils.makeVec3(point2) - return mist.vec.mag({x = point1.x - point2.x, y = 0, z = point1.z - point2.z}) - end - - --- Returns distance in meters between two points in 3D space. - -- @tparam Vec3 point1 first point - -- @tparam Vec3 point2 second point - -- @treturn number distancen between given points in 3D space. - function mist.utils.get3DDist(point1, point2) - if not point1 then - log:warn("mist.utils.get2DDist 1st input value is nil") - end - if not point2 then - log:warn("mist.utils.get2DDist 2nd input value is nil") - end - return mist.vec.mag({x = point1.x - point2.x, y = point1.y - point2.y, z = point1.z - point2.z}) - end - - --- Creates a waypoint from a vector. - -- @tparam Vec2|Vec3 vec position of the new waypoint - -- @treturn Waypoint a new waypoint to be used inside paths. - function mist.utils.vecToWP(vec) - local newWP = {} - newWP.x = vec.x - newWP.y = vec.y - if vec.z then - newWP.alt = vec.y - newWP.y = vec.z - else - newWP.alt = land.getHeight({x = vec.x, y = vec.y}) - end - return newWP - end - - --- Creates a waypoint from a unit. - -- This function also considers the units speed. - -- The alt_type of this waypoint is set to "BARO". - -- @tparam Unit pUnit Unit whose position and speed will be used. - -- @treturn Waypoint new waypoint. - function mist.utils.unitToWP(pUnit) - local unit = mist.utils.deepCopy(pUnit) - if type(unit) == 'string' then - if Unit.getByName(unit) then - unit = Unit.getByName(unit) - end - end - if unit:isExist() == true then - local new = mist.utils.vecToWP(unit:getPosition().p) - new.speed = mist.vec.mag(unit:getVelocity()) - new.alt_type = "BARO" - - return new - end - log:error("$1 not found or doesn't exist", pUnit) - return false - end - - --- Creates a deep copy of a object. - -- Usually this object is a table. - -- See also: from http://lua-users.org/wiki/CopyTable - -- @param object object to copy - -- @return copy of object - function mist.utils.deepCopy(object) - local lookup_table = {} - local function _copy(object) - if type(object) ~= "table" then - return object - elseif lookup_table[object] then - return lookup_table[object] - end - local new_table = {} - lookup_table[object] = new_table - for index, value in pairs(object) do - new_table[_copy(index)] = _copy(value) - end - return setmetatable(new_table, getmetatable(object)) - end - return _copy(object) - end - - --- Simple rounding function. - -- From http://lua-users.org/wiki/SimpleRound - -- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place - -- @tparam number num number to round - -- @param idp - function mist.utils.round(num, idp) - local mult = 10^(idp or 0) - return math.floor(num * mult + 0.5) / mult - end - - --- Rounds all numbers inside a table. - -- @tparam table tbl table in which to round numbers - -- @param idp - function mist.utils.roundTbl(tbl, idp) - for id, val in pairs(tbl) do - if type(val) == 'number' then - tbl[id] = mist.utils.round(val, idp) - end - end - return tbl - end - - --- Executes the given string. - -- borrowed from Slmod - -- @tparam string s string containing LUA code. - -- @treturn boolean true if successfully executed, false otherwise - function mist.utils.dostring(s) - local f, err = loadstring(s) - if f then - return true, f() - else - return false, err - end - end - - --- Checks a table's types. - -- This function checks a tables types against a specifically forged type table. - -- @param fname - -- @tparam table type_tbl - -- @tparam table var_tbl - -- @usage -- specifically forged type table - -- type_tbl = { - -- {'table', 'number'}, - -- 'string', - -- 'number', - -- 'number', - -- {'string','nil'}, - -- {'number', 'nil'} - -- } - -- -- my_tbl index 1 must be a table or a number; - -- -- index 2, a string; index 3, a number; - -- -- index 4, a number; index 5, either a string or nil; - -- -- and index 6, either a number or nil. - -- mist.utils.typeCheck(type_tbl, my_tb) - -- @return true if table passes the check, false otherwise. - function mist.utils.typeCheck(fname, type_tbl, var_tbl) - -- log:info('type check') - for type_key, type_val in pairs(type_tbl) do - -- log:info('type_key: $1 type_val: $2', type_key, type_val) - - --type_key can be a table of accepted keys- so try to find one that is not nil - local type_key_str = '' - local act_key = type_key -- actual key within var_tbl - necessary to use for multiple possible key variables. Initialize to type_key - if type(type_key) == 'table' then - - for i = 1, #type_key do - if i ~= 1 then - type_key_str = type_key_str .. '/' - end - type_key_str = type_key_str .. tostring(type_key[i]) - if var_tbl[type_key[i]] ~= nil then - act_key = type_key[i] -- found a non-nil entry, make act_key now this val. - end - end - else - type_key_str = tostring(type_key) - end - - local err_msg = 'Error in function ' .. fname .. ', parameter "' .. type_key_str .. '", expected: ' - local passed_check = false - - if type(type_tbl[type_key]) == 'table' then - -- log:info('err_msg, before: $1', err_msg) - for j = 1, #type_tbl[type_key] do - - if j == 1 then - err_msg = err_msg .. type_tbl[type_key][j] - else - err_msg = err_msg .. ' or ' .. type_tbl[type_key][j] - end - - if type(var_tbl[act_key]) == type_tbl[type_key][j] then - passed_check = true - end - end - -- log:info('err_msg, after: $1', err_msg) - else - -- log:info('err_msg, before: $1', err_msg) - err_msg = err_msg .. type_tbl[type_key] - -- log:info('err_msg, after: $1', err_msg) - if type(var_tbl[act_key]) == type_tbl[type_key] then - passed_check = true - end - - end - - if not passed_check then - err_msg = err_msg .. ', got ' .. type(var_tbl[act_key]) - return false, err_msg - end - end - return true - end - - --- Serializes the give variable to a string. - -- borrowed from slmod - -- @param var variable to serialize - -- @treturn string variable serialized to string - function mist.utils.basicSerialize(var) - if var == nil then - return "\"\"" - else - if ((type(var) == 'number') or - (type(var) == 'boolean') or - (type(var) == 'function') or - (type(var) == 'table') or - (type(var) == 'userdata') ) then - return tostring(var) - elseif type(var) == 'string' then - var = string.format('%q', var) - return var - end - end -end - ---- Serialize value --- borrowed from slmod (serialize_slmod) --- @param name --- @param value value to serialize --- @param level -function mist.utils.serialize(name, value, level) - --Based on ED's serialize_simple2 - local function basicSerialize(o) - if type(o) == "number" then - return tostring(o) - elseif type(o) == "boolean" then - return tostring(o) - else -- assume it is a string - return mist.utils.basicSerialize(o) - end - end - - local function serializeToTbl(name, value, level) - local var_str_tbl = {} - if level == nil then - level = "" - end - if level ~= "" then - level = level.."" - end - table.insert(var_str_tbl, level .. name .. " = ") - - if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then - table.insert(var_str_tbl, basicSerialize(value) .. ",\n") - elseif type(value) == "table" then - table.insert(var_str_tbl, "\n"..level.."{\n") - - for k,v in pairs(value) do -- serialize its fields - local key - if type(k) == "number" then - key = string.format("[%s]", k) - else - key = string.format("[%q]", k) - end - table.insert(var_str_tbl, mist.utils.serialize(key, v, level.." ")) - - end - if level == "" then - table.insert(var_str_tbl, level.."} -- end of "..name.."\n") - - else - table.insert(var_str_tbl, level.."}, -- end of "..name.."\n") - - end - else - log:error('Cannot serialize a $1', type(value)) - end - return var_str_tbl - end - - local t_str = serializeToTbl(name, value, level) - - return table.concat(t_str) -end - ---- Serialize value supporting cycles. --- borrowed from slmod (serialize_wcycles) --- @param name --- @param value value to serialize --- @param saved -function mist.utils.serializeWithCycles(name, value, saved) - --mostly straight out of Programming in Lua - local function basicSerialize(o) - if type(o) == "number" then - return tostring(o) - elseif type(o) == "boolean" then - return tostring(o) - else -- assume it is a string - return mist.utils.basicSerialize(o) - end - end - - local t_str = {} - saved = saved or {} -- initial value - if ((type(value) == 'string') or (type(value) == 'number') or (type(value) == 'table') or (type(value) == 'boolean')) then - table.insert(t_str, name .. " = ") - if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then - table.insert(t_str, basicSerialize(value) .. "\n") - else - - if saved[value] then -- value already saved? - table.insert(t_str, saved[value] .. "\n") - else - saved[value] = name -- save name for next time - table.insert(t_str, "{}\n") - for k,v in pairs(value) do -- save its fields - local fieldname = string.format("%s[%s]", name, basicSerialize(k)) - table.insert(t_str, mist.utils.serializeWithCycles(fieldname, v, saved)) - end - end - end - return table.concat(t_str) - else - return "" - end -end - ---- Serialize a table to a single line string. --- serialization of a table all on a single line, no comments, made to replace old get_table_string function --- borrowed from slmod --- @tparam table tbl table to serialize. --- @treturn string string containing serialized table -function mist.utils.oneLineSerialize(tbl) - if type(tbl) == 'table' then --function only works for tables! - - local tbl_str = {} - - tbl_str[#tbl_str + 1] = '{ ' - - for ind,val in pairs(tbl) do -- serialize its fields - if type(ind) == "number" then - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = tostring(ind) - tbl_str[#tbl_str + 1] = '] = ' - else --must be a string - tbl_str[#tbl_str + 1] = '[' - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) - tbl_str[#tbl_str + 1] = '] = ' - end - - if ((type(val) == 'number') or (type(val) == 'boolean')) then - tbl_str[#tbl_str + 1] = tostring(val) - tbl_str[#tbl_str + 1] = ', ' - elseif type(val) == 'string' then - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) - tbl_str[#tbl_str + 1] = ', ' - elseif type(val) == 'nil' then -- won't ever happen, right? - tbl_str[#tbl_str + 1] = 'nil, ' - elseif type(val) == 'table' then - tbl_str[#tbl_str + 1] = mist.utils.oneLineSerialize(val) - tbl_str[#tbl_str + 1] = ', ' --I think this is right, I just added it - else - log:warn('Unable to serialize value type $1 at index $2', mist.utils.basicSerialize(type(val)), tostring(ind)) - end - - end - tbl_str[#tbl_str + 1] = '}' - return table.concat(tbl_str) - else - return mist.utils.basicSerialize(tbl) - end -end - ---- Returns table in a easy readable string representation. --- this function is not meant for serialization because it uses --- newlines for better readability. --- @param tbl table to show --- @param loc --- @param indent --- @param tableshow_tbls --- @return human readable string representation of given table -function mist.utils.tableShow(tbl, loc, indent, tableshow_tbls) --based on serialize_slmod, this is a _G serialization - tableshow_tbls = tableshow_tbls or {} --create table of tables - loc = loc or "" - indent = indent or "" - if type(tbl) == 'table' then --function only works for tables! - tableshow_tbls[tbl] = loc - - local tbl_str = {} - - tbl_str[#tbl_str + 1] = indent .. '{\n' - - for ind,val in pairs(tbl) do -- serialize its fields - if type(ind) == "number" then - tbl_str[#tbl_str + 1] = indent - tbl_str[#tbl_str + 1] = loc .. '[' - tbl_str[#tbl_str + 1] = tostring(ind) - tbl_str[#tbl_str + 1] = '] = ' - else - tbl_str[#tbl_str + 1] = indent - tbl_str[#tbl_str + 1] = loc .. '[' - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(ind) - tbl_str[#tbl_str + 1] = '] = ' - end - - if ((type(val) == 'number') or (type(val) == 'boolean')) then - tbl_str[#tbl_str + 1] = tostring(val) - tbl_str[#tbl_str + 1] = ',\n' - elseif type(val) == 'string' then - tbl_str[#tbl_str + 1] = mist.utils.basicSerialize(val) - tbl_str[#tbl_str + 1] = ',\n' - elseif type(val) == 'nil' then -- won't ever happen, right? - tbl_str[#tbl_str + 1] = 'nil,\n' - elseif type(val) == 'table' then - if tableshow_tbls[val] then - tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n' - else - tableshow_tbls[val] = loc .. '[' .. mist.utils.basicSerialize(ind) .. ']' - tbl_str[#tbl_str + 1] = tostring(val) .. ' ' - tbl_str[#tbl_str + 1] = mist.utils.tableShow(val, loc .. '[' .. mist.utils.basicSerialize(ind).. ']', indent .. ' ', tableshow_tbls) - tbl_str[#tbl_str + 1] = ',\n' - end - elseif type(val) == 'function' then - if debug and debug.getinfo then - local fcnname = tostring(val) - local info = debug.getinfo(val, "S") - if info.what == "C" then - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n' - else - if (string.sub(info.source, 1, 2) == [[./]]) then - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n' - else - tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' - end - end - - else - tbl_str[#tbl_str + 1] = 'a function,\n' - end - else - tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. mist.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind) - end - end - - tbl_str[#tbl_str + 1] = indent .. '}' - return table.concat(tbl_str) - end -end -end - ---- Debug functions --- @section mist.debug -do -- mist.debug scope - mist.debug = {} - - function mist.debug.changeSetting(s) - if type(s) == 'table' then - for sName, sVal in pairs(s) do - if type(sVal) == 'string' or type(sVal) == 'number' then - if sName == 'log' then - mistSettings[sName] = sVal - mist.log:setLevel(sVal) - elseif sName == 'dbLog' then - mistSettings[sName] = sVal - dblog:setLevel(sVal) - end - else - mistSettings[sName] = sVal - end - end - end - end - --- Dumps the global table _G. - -- This dumps the global table _G to a file in - -- the DCS\Logs directory. - -- This function requires you to disable script sanitization - -- in $DCS_ROOT\Scripts\MissionScripting.lua to access lfs and io - -- libraries. - -- @param fname - function mist.debug.dump_G(fname, simp) - if lfs and io then - local fdir = lfs.writedir() .. [[Logs\]] .. fname - local f = io.open(fdir, 'w') - if simp then - local g = mist.utils.deepCopy(_G) - g.mist = nil - g.slmod = nil - g.env.mission = nil - g.env.warehouses = nil - g.country.by_idx = nil - g.country.by_country = nil - - f:write(mist.utils.tableShow(g)) - else - - f:write(mist.utils.tableShow(_G)) - end - f:close() - log:info('Wrote debug data to $1', fdir) - --trigger.action.outText(errmsg, 10) - else - log:alert('insufficient libraries to run mist.debug.dump_G, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua') - --trigger.action.outText(errmsg, 10) - end - end - - --- Write debug data to file. - -- This function requires you to disable script sanitization - -- in $DCS_ROOT\Scripts\MissionScripting.lua to access lfs and io - -- libraries. - -- @param fcn - -- @param fcnVars - -- @param fname - function mist.debug.writeData(fcn, fcnVars, fname) - if lfs and io then - local fdir = lfs.writedir() .. [[Logs\]] .. fname - local f = io.open(fdir, 'w') - f:write(fcn(unpack(fcnVars, 1, table.maxn(fcnVars)))) - f:close() - log:info('Wrote debug data to $1', fdir) - local errmsg = 'mist.debug.writeData wrote data to ' .. fdir - trigger.action.outText(errmsg, 10) - else - local errmsg = 'Error: insufficient libraries to run mist.debug.writeData, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua' - log:alert(errmsg) - trigger.action.outText(errmsg, 10) - end - end - - --- Write mist databases to file. - -- This function requires you to disable script sanitization - -- in $DCS_ROOT\Scripts\MissionScripting.lua to access lfs and io - -- libraries. - function mist.debug.dumpDBs() - for DBname, DB in pairs(mist.DBs) do - if type(DB) == 'table' and type(DBname) == 'string' then - mist.debug.writeData(mist.utils.serialize, {DBname, DB}, 'mist_DBs_' .. DBname .. '.lua') - end - end - end - - -- write group table - function mist.debug.writeGroup(gName, data) - if gName and mist.DBs.groupsByName[gName] then - local dat - if data then - dat = mist.getGroupData(gName) - else - dat = mist.getGroupTable(gName) - end - if dat then - dat.route = {points = mist.getGroupRoute(gName, true)} - end - - if io and lfs and dat then - mist.debug.writeData(mist.utils.serialize, {gName, dat}, gName .. '_table.lua') - else - if dat then - trigger.action.outText('Error: insufficient libraries to run mist.debug.writeGroup, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua \nGroup table written to DCS.log file instead.', 10) - log:warn('$1 dataTable: $2', gName, dat) - else - trigger.action.outText('Unable to write group table for: ' .. gName .. '\n Error: insufficient libraries to run mist.debug.writeGroup, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua', 10) - end - end - end - end - - - - -- write all object types in mission. - function mist.debug.writeTypes(fName) - local wt = 'mistDebugWriteTypes.lua' - if fName and type(fName) == 'string' and string.find(fName, '.lua') then - wt = fName - end - local output = {units = {}, countries = {}} - for coa_name_miz, coa_data in pairs(env.mission.coalition) do - if type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - local countryName = string.lower(cntry_data.name) - if cntry_data.id and country.names[cntry_data.id] then - countryName = string.lower(country.names[cntry_data.id]) - end - output.countries[countryName] = {} - if type(cntry_data) == 'table' then --just making sure - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" or obj_cat_name == "static" then --should be an unncessary check - local category = obj_cat_name - if not output.countries[countryName][category] then - -- log:warn('Create: $1', category) - output.countries[countryName][category] = {} - end - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.units and type(group_data.units) == 'table' then --making sure again- this is a valid group - for i = 1, #group_data.units do - if group_data.units[i] then - local u = group_data.units[i] - local liv = u.livery_id or 'default' - if not output.units[u.type] then -- create unit table - -- log:warn('Create: $1', u.type) - output.units[u.type] = {count = 0, livery_id = {}} - end - - if not output.countries[countryName][category][u.type] then - -- log:warn('Create country, category, unit: $1', u.type) - output.countries[countryName][category][u.type] = 0 - end - -- add to count - output.countries[countryName][category][u.type] = output.countries[countryName][category][u.type] + 1 - output.units[u.type].count = output.units[u.type].count + 1 - - if liv and not output.units[u.type].livery_id[countryName] then - -- log:warn('Create livery country: $1', countryName) - output.units[u.type].livery_id[countryName] = {} - end - if liv and not output.units[u.type].livery_id[countryName][liv] then - --log:warn('Create Livery: $1', liv) - output.units[u.type].livery_id[countryName][liv] = 0 - end - if liv then - output.units[u.type].livery_id[countryName][liv] = output.units[u.type].livery_id[countryName][liv] + 1 - end - if u.payload and u.payload.pylons then - if not output.units[u.type].CLSID then - output.units[u.type].CLSID = {} - output.units[u.type].pylons = {} - end - - for pyIndex, pData in pairs(u.payload.pylons) do - if not output.units[u.type].CLSID[pData.CLSID] then - output.units[u.type].CLSID[pData.CLSID] = 0 - end - output.units[u.type].CLSID[pData.CLSID] = output.units[u.type].CLSID[pData.CLSID] + 1 - - if not output.units[u.type].pylons[pyIndex] then - output.units[u.type].pylons[pyIndex] = {} - end - if not output.units[u.type].pylons[pyIndex][pData.CLSID] then - output.units[u.type].pylons[pyIndex][pData.CLSID] = 0 - end - output.units[u.type].pylons[pyIndex][pData.CLSID] = output.units[u.type].pylons[pyIndex][pData.CLSID] + 1 - end - - end - end - end - end - end - end - end - end - end - end - end - end - end - if io and lfs then - mist.debug.writeData(mist.utils.serialize, {'mistDebugWriteTypes', output}, wt) - else - trigger.action.outText('Error: insufficient libraries to run mist.debug.writeTypes, you must disable the sanitization of the io and lfs libraries in ./Scripts/MissionScripting.lua \n writeTypes table written to DCS.log file instead.', 10) - log:warn('mist.debug.writeTypes: $1', output) - end - return output - end - function mist.debug.writeWeapons(unit) - - end - - function mist.debug.mark(msg, coord) - - mist.marker.add({point = coord, text = msg}) - log:warn('debug.mark: $1 $2', msg, coord) - end -end - ---- 3D Vector functions --- @section mist.vec -do -- mist.vec scope - mist.vec = {} - - --- Vector addition. - -- @tparam Vec3 vec1 first vector - -- @tparam Vec3 vec2 second vector - -- @treturn Vec3 new vector, sum of vec1 and vec2. - function mist.vec.add(vec1, vec2) - return {x = vec1.x + vec2.x, y = vec1.y + vec2.y, z = vec1.z + vec2.z} - end - - --- Vector substraction. - -- @tparam Vec3 vec1 first vector - -- @tparam Vec3 vec2 second vector - -- @treturn Vec3 new vector, vec2 substracted from vec1. - function mist.vec.sub(vec1, vec2) - return {x = vec1.x - vec2.x, y = vec1.y - vec2.y, z = vec1.z - vec2.z} - end - - --- Vector scalar multiplication. - -- @tparam Vec3 vec vector to multiply - -- @tparam number mult scalar multiplicator - -- @treturn Vec3 new vector multiplied with the given scalar - function mist.vec.scalarMult(vec, mult) - return {x = vec.x*mult, y = vec.y*mult, z = vec.z*mult} - end - - mist.vec.scalar_mult = mist.vec.scalarMult - - --- Vector dot product. - -- @tparam Vec3 vec1 first vector - -- @tparam Vec3 vec2 second vector - -- @treturn number dot product of given vectors - function mist.vec.dp (vec1, vec2) - return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z - end - - --- Vector cross product. - -- @tparam Vec3 vec1 first vector - -- @tparam Vec3 vec2 second vector - -- @treturn Vec3 new vector, cross product of vec1 and vec2. - function mist.vec.cp(vec1, vec2) - return { x = vec1.y*vec2.z - vec1.z*vec2.y, y = vec1.z*vec2.x - vec1.x*vec2.z, z = vec1.x*vec2.y - vec1.y*vec2.x} - end - - --- Vector magnitude - -- @tparam Vec3 vec vector - -- @treturn number magnitude of vector vec - function mist.vec.mag(vec) - return (vec.x^2 + vec.y^2 + vec.z^2)^0.5 - end - - --- Unit vector - -- @tparam Vec3 vec - -- @treturn Vec3 unit vector of vec - function mist.vec.getUnitVec(vec) - local mag = mist.vec.mag(vec) - return { x = vec.x/mag, y = vec.y/mag, z = vec.z/mag } - end - - --- Rotate vector. - -- @tparam Vec2 vec2 to rotoate - -- @tparam number theta - -- @return Vec2 rotated vector. - function mist.vec.rotateVec2(vec2, theta) - return { x = vec2.x*math.cos(theta) - vec2.y*math.sin(theta), y = vec2.x*math.sin(theta) + vec2.y*math.cos(theta)} - end - - function mist.vec.normalize(vec3) - local mag = mist.vec.mag(vec3) - if mag ~= 0 then - return mist.vec.scalar_mult(vec3, 1.0 / mag) - end - end -end - ---- Flag functions. --- The mist "Flag functions" are functions that are similar to Slmod functions --- that detect a game condition and set a flag when that game condition is met. --- --- They are intended to be used by persons with little or no experience in Lua --- programming, but with a good knowledge of the DCS mission editor. --- @section mist.flagFunc -do -- mist.flagFunc scope - mist.flagFunc = {} - - --- Sets a flag if map objects are destroyed inside a zone. - -- Once this function is run, it will start a continuously evaluated process - -- that will set a flag true if map objects (such as bridges, buildings in - -- town, etc.) die (or have died) in a mission editor zone (or set of zones). - -- This will only happen once; once the flag is set true, the process ends. - -- @usage - -- -- Example vars table - -- vars = { - -- zones = { "zone1", "zone2" }, -- can also be a single string - -- flag = 3, -- number of the flag - -- stopflag = 4, -- optional number of the stop flag - -- req_num = 10, -- optional minimum amount of map objects needed to die - -- } - -- mist.flagFuncs.mapobjs_dead_zones(vars) - -- @tparam table vars table containing parameters. - function mist.flagFunc.mapobjs_dead_zones(vars) - --[[vars needs to be: -zones = table or string, -flag = number, -stopflag = number or nil, -req_num = number or nil - -AND used by function, -initial_number - -]] - -- type_tbl - local type_tbl = { - [{'zones', 'zone'}] = {'table', 'string'}, - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_zones', type_tbl, vars) - assert(err, errmsg) - local zones = vars.zones or vars.zone - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local req_num = vars.req_num or vars.reqnum or 1 - local initial_number = vars.initial_number - - if type(zones) == 'string' then - zones = {zones} - end - - if not initial_number then - initial_number = #mist.getDeadMapObjsInZones(zones) - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (#mist.getDeadMapObjsInZones(zones) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - return - else - mist.scheduleFunction(mist.flagFunc.mapobjs_dead_zones, {{zones = zones, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) - end - end - end - - --- Sets a flag if map objects are destroyed inside a polygon. - -- Once this function is run, it will start a continuously evaluated process - -- that will set a flag true if map objects (such as bridges, buildings in - -- town, etc.) die (or have died) in a polygon. - -- This will only happen once; once the flag is set true, the process ends. - -- @usage - -- -- Example vars table - -- vars = { - -- zone = { - -- [1] = mist.DBs.unitsByName['NE corner'].point, - -- [2] = mist.DBs.unitsByName['SE corner'].point, - -- [3] = mist.DBs.unitsByName['SW corner'].point, - -- [4] = mist.DBs.unitsByName['NW corner'].point - -- } - -- flag = 3, -- number of the flag - -- stopflag = 4, -- optional number of the stop flag - -- req_num = 10, -- optional minimum amount of map objects needed to die - -- } - -- mist.flagFuncs.mapobjs_dead_zones(vars) - -- @tparam table vars table containing parameters. - function mist.flagFunc.mapobjs_dead_polygon(vars) - --[[vars needs to be: -zone = table, -flag = number, -stopflag = number or nil, -req_num = number or nil - -AND used by function, -initial_number - -]] - -- type_tbl - local type_tbl = { - [{'zone', 'polyzone'}] = 'table', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.mapobjs_dead_polygon', type_tbl, vars) - assert(err, errmsg) - local zone = vars.zone or vars.polyzone - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local req_num = vars.req_num or vars.reqnum or 1 - local initial_number = vars.initial_number - - if not initial_number then - initial_number = #mist.getDeadMapObjsInPolygonZone(zone) - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (#mist.getDeadMapObjsInPolygonZone(zone) - initial_number) >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - return - else - mist.scheduleFunction(mist.flagFunc.mapobjs_dead_polygon, {{zone = zone, flag = flag, stopflag = stopflag, req_num = req_num, initial_number = initial_number}}, timer.getTime() + 1) - end - end - end - - --- Sets a flag if unit(s) is/are inside a polygon. - -- @tparam table vars @{unitsInPolygonVars} - -- @usage -- set flag 11 to true as soon as any blue vehicles - -- -- are inside the polygon shape created off of the waypoints - -- -- of the group forest1 - -- mist.flagFunc.units_in_polygon { - -- units = {'[blue][vehicle]'}, - -- zone = mist.getGroupPoints('forest1'), - -- flag = 11 - -- } - function mist.flagFunc.units_in_polygon(vars) - --[[vars needs to be: -units = table, -zone = table, -flag = number, -stopflag = number or nil, -maxalt = number or nil, -interval = number or nil, -req_num = number or nil -toggle = boolean or nil -unitTableDef = table or nil -]] - -- type_tbl - local type_tbl = { - [{'units', 'unit'}] = 'table', - [{'zone', 'polyzone'}] = 'table', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'maxalt', 'alt'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_polygon', type_tbl, vars) - assert(err, errmsg) - local units = vars.units or vars.unit - local zone = vars.zone or vars.polyzone - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local maxalt = vars.maxalt or vars.alt - local req_num = vars.req_num or vars.reqnum or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - if unitTableDef then - units = mist.makeUnitTable(unitTableDef) - end - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then - local num_in_zone = 0 - for i = 1, #units do - local unit = Unit.getByName(units[i]) or StaticObject.getByName(units[i]) - if unit then - local pos = unit:getPosition().p - if mist.pointInPolygon(pos, zone, maxalt) then - num_in_zone = num_in_zone + 1 - if num_in_zone >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - break - end - end - end - end - if toggle and (num_in_zone < req_num) and trigger.misc.getUserFlag(flag) > 0 then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == 0) then - mist.scheduleFunction(mist.flagFunc.units_in_polygon, {{units = units, zone = zone, flag = flag, stopflag = stopflag, interval = interval, req_num = req_num, maxalt = maxalt, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) - end - end - - end - - --- Sets a flag if unit(s) is/are inside a trigger zone. - -- @todo document - function mist.flagFunc.units_in_zones(vars) - --[[vars needs to be: - units = table, - zones = table, - flag = number, - stopflag = number or nil, - zone_type = string or nil, - req_num = number or nil, - interval = number or nil - toggle = boolean or nil - ]] - -- type_tbl - local type_tbl = { - units = 'table', - zones = 'table', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'zone_type', 'zonetype'}] = {'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_zones', type_tbl, vars) - assert(err, errmsg) - local units = vars.units - local zones = vars.zones - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local zone_type = vars.zone_type or vars.zonetype or 'cylinder' - local req_num = vars.req_num or vars.reqnum or 1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - if unitTableDef then - units = mist.makeUnitTable(unitTableDef) - end - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local in_zone_units = mist.getUnitsInZones(units, zones, zone_type) - - if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #in_zone_units < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_in_zones, {{units = units, zones = zones, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef}}, timer.getTime() + interval) - end - end - - end - --[[ - function mist.flagFunc.weapon_in_zones(vars) - -- borrow from suchoi surprise. While running enabled event handler that checks for weapons in zone. - -- Choice is weapon category or weapon strings. - - end -]] - --- Sets a flag if unit(s) is/are inside a moving zone. - -- @todo document - function mist.flagFunc.units_in_moving_zones(vars) - --[[vars needs to be: - units = table, - zone_units = table, - radius = number, - flag = number, - stopflag = number or nil, - zone_type = string or nil, - req_num = number or nil, - interval = number or nil - toggle = boolean or nil - ]] - -- type_tbl - local type_tbl = { - units = 'table', - [{'zone_units', 'zoneunits'}] = 'table', - radius = 'number', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'zone_type', 'zonetype'}] = {'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef = {'table', 'nil'}, - zUnitTableDef = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_in_moving_zones', type_tbl, vars) - assert(err, errmsg) - local units = vars.units - local zone_units = vars.zone_units or vars.zoneunits - local radius = vars.radius - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local zone_type = vars.zone_type or vars.zonetype or 'cylinder' - local req_num = vars.req_num or vars.reqnum or 1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - local unitTableDef = vars.unitTableDef - local zUnitTableDef = vars.zUnitTableDef - - if not units.processed then - unitTableDef = mist.utils.deepCopy(units) - end - - if not zone_units.processed then - zUnitTableDef = mist.utils.deepCopy(zone_units) - end - - if (units.processed and units.processed < mist.getLastDBUpdateTime()) or not units.processed then -- run unit table short cuts - if unitTableDef then - units = mist.makeUnitTable(unitTableDef) - end - end - - if (zone_units.processed and zone_units.processed < mist.getLastDBUpdateTime()) or not zone_units.processed then -- run unit table short cuts - if zUnitTableDef then - zone_units = mist.makeUnitTable(zUnitTableDef) - end - - end - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local in_zone_units = mist.getUnitsInMovingZones(units, zone_units, radius, zone_type) - - if #in_zone_units >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #in_zone_units < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_in_moving_zones, {{units = units, zone_units = zone_units, radius = radius, flag = flag, stopflag = stopflag, zone_type = zone_type, req_num = req_num, interval = interval, toggle = toggle, unitTableDef = unitTableDef, zUnitTableDef = zUnitTableDef}}, timer.getTime() + interval) - end - end - - end - - --- Sets a flag if units have line of sight to each other. - -- @todo document - function mist.flagFunc.units_LOS(vars) - --[[vars needs to be: -unitset1 = table, -altoffset1 = number, -unitset2 = table, -altoffset2 = number, -flag = number, -stopflag = number or nil, -radius = number or nil, -interval = number or nil, -req_num = number or nil -toggle = boolean or nil -]] - -- type_tbl - local type_tbl = { - [{'unitset1', 'units1'}] = 'table', - [{'altoffset1', 'alt1'}] = 'number', - [{'unitset2', 'units2'}] = 'table', - [{'altoffset2', 'alt2'}] = 'number', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - [{'req_num', 'reqnum'}] = {'number', 'nil'}, - interval = {'number', 'nil'}, - radius = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - unitTableDef1 = {'table', 'nil'}, - unitTableDef2 = {'table', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.units_LOS', type_tbl, vars) - assert(err, errmsg) - local unitset1 = vars.unitset1 or vars.units1 - local altoffset1 = vars.altoffset1 or vars.alt1 - local unitset2 = vars.unitset2 or vars.units2 - local altoffset2 = vars.altoffset2 or vars.alt2 - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local radius = vars.radius or math.huge - local req_num = vars.req_num or vars.reqnum or 1 - local toggle = vars.toggle or nil - local unitTableDef1 = vars.unitTableDef1 - local unitTableDef2 = vars.unitTableDef2 - - if not unitset1.processed then - unitTableDef1 = mist.utils.deepCopy(unitset1) - end - - if not unitset2.processed then - unitTableDef2 = mist.utils.deepCopy(unitset2) - end - - if (unitset1.processed and unitset1.processed < mist.getLastDBUpdateTime()) or not unitset1.processed then -- run unit table short cuts - if unitTableDef1 then - unitset1 = mist.makeUnitTable(unitTableDef1) - end - end - - if (unitset2.processed and unitset2.processed < mist.getLastDBUpdateTime()) or not unitset2.processed then -- run unit table short cuts - if unitTableDef2 then - unitset2 = mist.makeUnitTable(unitTableDef2) - end - end - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - - local unitLOSdata = mist.getUnitsLOS(unitset1, altoffset1, unitset2, altoffset2, radius) - - if #unitLOSdata >= req_num and trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - elseif #unitLOSdata < req_num and toggle then - trigger.action.setUserFlag(flag, false) - end - -- do another check in case stopflag was set true by this function - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.units_LOS, {{unitset1 = unitset1, altoffset1 = altoffset1, unitset2 = unitset2, altoffset2 = altoffset2, flag = flag, stopflag = stopflag, radius = radius, req_num = req_num, interval = interval, toggle = toggle, unitTableDef1 = unitTableDef1, unitTableDef2 = unitTableDef2}}, timer.getTime() + interval) - end - end - end - - --- Sets a flag if group is alive. - -- @todo document - function mist.flagFunc.group_alive(vars) - --[[vars -groupName -flag -toggle -interval -stopFlag - -]] - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true and #Group.getByName(groupName):getUnits() > 0 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) - end - - end - - --- Sets a flag if group is dead. - -- @todo document - function mist.flagFunc.group_dead(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_dead', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if (Group.getByName(groupName) and Group.getByName(groupName):isExist() == false) or (Group.getByName(groupName) and #Group.getByName(groupName):getUnits() < 1) or not Group.getByName(groupName) then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_dead, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle}}, timer.getTime() + interval) - end - end - - --- Sets a flag if less than given percent of group is alive. - -- @todo document - function mist.flagFunc.group_alive_less_than(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - percent = 'number', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_less_than', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local percent = vars.percent - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() < percent/100 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle then - trigger.action.setUserFlag(flag, false) - end - end - else - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive_less_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) - end - end - - --- Sets a flag if more than given percent of group is alive. - -- @todo document - function mist.flagFunc.group_alive_more_than(vars) - local type_tbl = { - [{'group', 'groupname', 'gp', 'groupName'}] = 'string', - percent = 'number', - flag = {'number', 'string'}, - [{'stopflag', 'stopFlag'}] = {'number', 'string', 'nil'}, - interval = {'number', 'nil'}, - toggle = {'boolean', 'nil'}, - } - - local err, errmsg = mist.utils.typeCheck('mist.flagFunc.group_alive_more_than', type_tbl, vars) - assert(err, errmsg) - - local groupName = vars.groupName or vars.group or vars.gp or vars.Groupname - local flag = vars.flag - local percent = vars.percent - local stopflag = vars.stopflag or vars.stopFlag or -1 - local interval = vars.interval or 1 - local toggle = vars.toggle or nil - - - if stopflag == -1 or (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - if Group.getByName(groupName) and Group.getByName(groupName):isExist() == true then - if Group.getByName(groupName):getSize()/Group.getByName(groupName):getInitialSize() > percent/100 then - if trigger.misc.getUserFlag(flag) == 0 then - trigger.action.setUserFlag(flag, true) - end - else - if toggle and trigger.misc.getUserFlag(flag) == 1 then - trigger.action.setUserFlag(flag, false) - end - end - else --- just in case - if toggle and trigger.misc.getUserFlag(flag) == 1 then - trigger.action.setUserFlag(flag, false) - end - end - end - - if (type(trigger.misc.getUserFlag(stopflag)) == 'number' and trigger.misc.getUserFlag(stopflag) == 0) or (type(trigger.misc.getUserFlag(stopflag)) == 'boolean' and trigger.misc.getUserFlag(stopflag) == false) then - mist.scheduleFunction(mist.flagFunc.group_alive_more_than, {{groupName = groupName, flag = flag, stopflag = stopflag, interval = interval, toggle = toggle, percent = percent}}, timer.getTime() + interval) - end - end - - mist.flagFunc.mapobjsDeadPolygon = mist.flagFunc.mapobjs_dead_polygon - mist.flagFunc.mapobjsDeadZones = mist.flagFunc.Mapobjs_dead_zones - mist.flagFunc.unitsInZones = mist.flagFunc.units_in_zones - mist.flagFunc.unitsInMovingZones = mist.flagFunc.units_in_moving_zones - mist.flagFunc.unitsInPolygon = mist.flagFunc.units_in_polygon - mist.flagFunc.unitsLOS = mist.flagFunc.units_LOS - mist.flagFunc.groupAlive = mist.flagFunc.group_alive - mist.flagFunc.groupDead = mist.flagFunc.group_dead - mist.flagFunc.groupAliveMoreThan = mist.flagFunc.group_alive_more_than - mist.flagFunc.groupAliveLessThan = mist.flagFunc.group_alive_less_than - -end - ---- Message functions. --- Messaging system --- @section mist.msg -do -- mist.msg scope - local messageList = {} - -- this defines the max refresh rate of the message box it honestly only needs to - -- go faster than this for precision timing stuff (which could be its own function) - local messageDisplayRate = 0.1 - local messageID = 0 - local displayActive = false - local displayFuncId = 0 - - local caSlots = false - local caMSGtoGroup = false - local anyUpdate = false - local lastMessageTime = nil - - if env.mission.groundControl then -- just to be sure? - for index, value in pairs(env.mission.groundControl) do - if type(value) == 'table' then - for roleName, roleVal in pairs(value) do - for rIndex, rVal in pairs(roleVal) do - if type(rVal) == 'number' and rVal > 0 then - caSlots = true - break - end - - end - end - elseif type(value) == 'boolean' and value == true then - caSlots = true - break - end - end - end - - local function mistdisplayV5() - --log:warn("mistdisplayV5: $1", timer.getTime()) - - local clearView = true - if #messageList > 0 then - --log:warn('Updates: $1', anyUpdate) - if anyUpdate == true then - local activeClients = {} - - for clientId, clientData in pairs(mist.DBs.humansById) do - if Unit.getByName(clientData.unitName) and Unit.getByName(clientData.unitName):isExist() == true then - activeClients[clientData.groupId] = clientData.groupName - end - end - anyUpdate = false - if displayActive == false then - displayActive = true - end - --mist.debug.writeData(mist.utils.serialize,{'msg', messageList}, 'messageList.lua') - local msgTableText = {} - local msgTableSound = {} - local curTime = timer.getTime() - for mInd, messageData in pairs(messageList) do - --log:warn(messageData) - if messageData.displayTill < curTime then - messageData:remove() -- now using the remove/destroy function. - else - if messageData.displayedFor then - messageData.displayedFor = curTime - messageData.addedAt - end - local nextSound = 1000 - local soundIndex = 0 - - if messageData.multSound and #messageData.multSound > 0 then - for index, sData in pairs(messageData.multSound) do - if sData.time <= messageData.displayedFor and sData.played == false and sData.time < nextSound then -- find index of the next sound to be played - nextSound = sData.time - soundIndex = index - end - end - if soundIndex ~= 0 then - messageData.multSound[soundIndex].played = true - end - end - - for recIndex, recData in pairs(messageData.msgFor) do -- iterate recipiants - if recData == 'RED' or recData == 'BLUE' or activeClients[recData] then -- rec exists - if messageData.text then -- text - if not msgTableText[recData] then -- create table entry for text - msgTableText[recData] = {} - msgTableText[recData].text = {} - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[1] = '-------Combined Arms Message-------- \n' - end - msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else -- add to table entry and adjust display time if needed - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- Combined Arms Message: \n' - else - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- \n' - end - table.insert(msgTableText[recData].text, messageData.text) - if msgTableText[recData].displayTime < messageData.displayTime - messageData.displayedFor then - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else - --msgTableText[recData].displayTime = 10 - end - end - end - if soundIndex ~= 0 then - msgTableSound[recData] = messageData.multSound[soundIndex].file - end - end - - end - messageData.update = nil - - end - - end - ------- new display - - if caSlots == true and caMSGtoGroup == false then - if msgTableText.RED then - trigger.action.outTextForCoalition(coalition.side.RED, table.concat(msgTableText.RED.text), msgTableText.RED.displayTime, clearView) - - end - if msgTableText.BLUE then - trigger.action.outTextForCoalition(coalition.side.BLUE, table.concat(msgTableText.BLUE.text), msgTableText.BLUE.displayTime, clearView) - end - end - - for index, msgData in pairs(msgTableText) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outTextForGroup(index, table.concat(msgData.text), msgData.displayTime, clearView) - end - end - --- new audio - if msgTableSound.RED then - trigger.action.outSoundForCoalition(coalition.side.RED, msgTableSound.RED) - end - if msgTableSound.BLUE then - trigger.action.outSoundForCoalition(coalition.side.BLUE, msgTableSound.BLUE) - end - - - for index, file in pairs(msgTableSound) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outSoundForGroup(index, file) - end - end - - end - - else - mist.removeFunction(displayFuncId) - displayActive = false - end - end - - local function mistdisplayV4() - local activeClients = {} - - for clientId, clientData in pairs(mist.DBs.humansById) do - if Unit.getByName(clientData.unitName) and Unit.getByName(clientData.unitName):isExist() == true then - activeClients[clientData.groupId] = clientData.groupName - end - end - - --[[if caSlots == true and caMSGtoGroup == true then - - end]] - - - if #messageList > 0 then - if displayActive == false then - displayActive = true - end - --mist.debug.writeData(mist.utils.serialize,{'msg', messageList}, 'messageList.lua') - local msgTableText = {} - local msgTableSound = {} - - for messageId, messageData in pairs(messageList) do - if messageData.displayedFor > messageData.displayTime then - messageData:remove() -- now using the remove/destroy function. - else - if messageData.displayedFor then - messageData.displayedFor = messageData.displayedFor + messageDisplayRate - end - local nextSound = 1000 - local soundIndex = 0 - - if messageData.multSound and #messageData.multSound > 0 then - for index, sData in pairs(messageData.multSound) do - if sData.time <= messageData.displayedFor and sData.played == false and sData.time < nextSound then -- find index of the next sound to be played - nextSound = sData.time - soundIndex = index - end - end - if soundIndex ~= 0 then - messageData.multSound[soundIndex].played = true - end - end - - for recIndex, recData in pairs(messageData.msgFor) do -- iterate recipiants - if recData == 'RED' or recData == 'BLUE' or activeClients[recData] then -- rec exists - if messageData.text then -- text - if not msgTableText[recData] then -- create table entry for text - msgTableText[recData] = {} - msgTableText[recData].text = {} - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[1] = '-------Combined Arms Message-------- \n' - end - msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else -- add to table entry and adjust display time if needed - if recData == 'RED' or recData == 'BLUE' then - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- Combined Arms Message: \n' - else - msgTableText[recData].text[#msgTableText[recData].text + 1] = '\n ---------------- \n' - end - msgTableText[recData].text[#msgTableText[recData].text + 1] = messageData.text - if msgTableText[recData].displayTime < messageData.displayTime - messageData.displayedFor then - msgTableText[recData].displayTime = messageData.displayTime - messageData.displayedFor - else - msgTableText[recData].displayTime = 1 - end - end - end - if soundIndex ~= 0 then - msgTableSound[recData] = messageData.multSound[soundIndex].file - end - end - end - - - end - end - ------- new display - - if caSlots == true and caMSGtoGroup == false then - if msgTableText.RED then - trigger.action.outTextForCoalition(coalition.side.RED, table.concat(msgTableText.RED.text), msgTableText.RED.displayTime, true) - - end - if msgTableText.BLUE then - trigger.action.outTextForCoalition(coalition.side.BLUE, table.concat(msgTableText.BLUE.text), msgTableText.BLUE.displayTime, true) - end - end - - for index, msgData in pairs(msgTableText) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outTextForGroup(index, table.concat(msgData.text), msgData.displayTime, true) - end - end - --- new audio - if msgTableSound.RED then - trigger.action.outSoundForCoalition(coalition.side.RED, msgTableSound.RED) - end - if msgTableSound.BLUE then - trigger.action.outSoundForCoalition(coalition.side.BLUE, msgTableSound.BLUE) - end - - - for index, file in pairs(msgTableSound) do - if type(index) == 'number' then -- its a groupNumber - trigger.action.outSoundForGroup(index, file) - end - end - else - mist.removeFunction(displayFuncId) - displayActive = false - end - - end - - local typeBase = { - ['Mi-8MT'] = {'Mi-8MTV2', 'Mi-8MTV', 'Mi-8'}, - ['MiG-21Bis'] = {'Mig-21'}, - ['MiG-15bis'] = {'Mig-15'}, - ['FW-190D9'] = {'FW-190'}, - ['Bf-109K-4'] = {'Bf-109'}, - } - - --[[function mist.setCAGroupMSG(val) - if type(val) == 'boolean' then - caMSGtoGroup = val - return true - end - return false -end]] - - mist.message = { - - add = function(vars) - local function msgSpamFilter(recList, spamBlockOn) - for id, name in pairs(recList) do - if name == spamBlockOn then - -- log:info('already on recList') - return recList - end - end - --log:info('add to recList') - table.insert(recList, spamBlockOn) - return recList - end - - --[[ - local vars = {} - vars.text = 'Hello World' - vars.displayTime = 20 - vars.msgFor = {coa = {'red'}, countries = {'Ukraine', 'Georgia'}, unitTypes = {'A-10C'}} - mist.message.add(vars) - - Displays the message for all red coalition players. Players belonging to Ukraine and Georgia, and all A-10Cs on the map - - ]] - - - local new = {} - new.text = vars.text -- The actual message - new.displayTime = vars.displayTime -- How long will the message appear for - new.displayedFor = 0 -- how long the message has been displayed so far - new.displayTill = timer.getTime() + vars.displayTime - new.name = vars.name -- ID to overwrite the older message (if it exists) Basically it replaces a message that is displayed with new text. - new.addedAt = timer.getTime() - --log:warn('New Message: $1', new.text) - - if vars.multSound and vars.multSound[1] then - new.multSound = vars.multSound - else - new.multSound = {} - end - - if vars.sound or vars.fileName then -- converts old sound file system into new multSound format - local sound = vars.sound - if vars.fileName then - sound = vars.fileName - end - new.multSound[#new.multSound+1] = {time = 0.1, file = sound} - end - - if #new.multSound > 0 then - for i, data in pairs(new.multSound) do - data.played = false - end - end - - local newMsgFor = {} -- list of all groups message displays for - for forIndex, forData in pairs(vars.msgFor) do - for list, listData in pairs(forData) do - for clientId, clientData in pairs(mist.DBs.humansById) do - forIndex = string.lower(forIndex) - if type(listData) == 'string' then - listData = string.lower(listData) - end - if (forIndex == 'coa' and (listData == string.lower(clientData.coalition) or listData == 'all')) or (forIndex == 'countries' and string.lower(clientData.country) == listData) or (forIndex == 'units' and string.lower(clientData.unitName) == listData) then -- - newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- so units dont get the same message twice if complex rules are given - --table.insert(newMsgFor, clientId) - elseif forIndex == 'unittypes' then - for typeId, typeData in pairs(listData) do - local found = false - for clientDataEntry, clientDataVal in pairs(clientData) do - if type(clientDataVal) == 'string' then - if mist.matchString(list, clientDataVal) == true or list == 'all' then - local sString = typeData - for rName, pTbl in pairs(typeBase) do -- just a quick check to see if the user may have meant something and got the specific type of the unit wrong - for pIndex, pName in pairs(pTbl) do - if mist.stringMatch(sString, pName) then - sString = rName - end - end - end - if sString == clientData.type then - found = true - newMsgFor = msgSpamFilter(newMsgFor, clientData.groupId) -- sends info oto other function to see if client is already recieving the current message. - --table.insert(newMsgFor, clientId) - end - end - end - if found == true then -- shouldn't this be elsewhere too? - break - end - end - end - - end - end - for coaData, coaId in pairs(coalition.side) do - if string.lower(forIndex) == 'coa' or string.lower(forIndex) == 'ca' then - if listData == string.lower(coaData) or listData == 'all' then - newMsgFor = msgSpamFilter(newMsgFor, coaData) - end - end - end - end - end - - if #newMsgFor > 0 then - new.msgFor = newMsgFor -- I swear its not confusing - - else - return false - end - - - if vars.name and type(vars.name) == 'string' then - for i = 1, #messageList do - if messageList[i].name then - if messageList[i].name == vars.name then - --log:info('updateMessage') - messageList[i].displayTill = timer.getTime() + messageList[i].displayTime - messageList[i].displayedFor = 0 - messageList[i].addedAt = timer.getTime() - messageList[i].sound = new.sound - messageList[i].text = new.text - messageList[i].msgFor = new.msgFor - messageList[i].multSound = new.multSound - anyUpdate = true - --log:warn('Message updated: $1', new.messageID) - return messageList[i].messageID - end - end - end - end - anyUpdate = true - messageID = messageID + 1 - new.messageID = messageID - - --mist.debug.writeData(mist.utils.serialize,{'msg', new}, 'newMsg.lua') - - - messageList[#messageList + 1] = new - - local mt = { __index = mist.message} - setmetatable(new, mt) - - if displayActive == false then - displayActive = true - displayFuncId = mist.scheduleFunction(mistdisplayV5, {}, timer.getTime() + messageDisplayRate, messageDisplayRate) - end - - return messageID - - end, - - remove = function(self) -- Now a self variable; the former functionality taken up by mist.message.removeById. - for i, msgData in pairs(messageList) do - if messageList[i] == self then - table.remove(messageList, i) - anyUpdate = true - return true --removal successful - end - end - return false -- removal not successful this script fails at life! - end, - - removeById = function(id) -- This function is NOT passed a self variable; it is the remove by id function. - for i, msgData in pairs(messageList) do - if messageList[i].messageID == id then - table.remove(messageList, i) - anyUpdate = true - return true --removal successful - end - end - return false -- removal not successful this script fails at life! - end, - } - - --[[ vars for mist.msgMGRS -vars.units - table of unit names (NOT unitNameTable- maybe this should change). -vars.acc - integer between 0 and 5, inclusive -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] - function mist.msgMGRS(vars) - local units = vars.units - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getMGRSString{units = units, acc = acc} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - end - - --[[ vars for mist.msgLL -vars.units - table of unit names (NOT unitNameTable- maybe this should change) (Yes). -vars.acc - integer, number of numbers after decimal place -vars.DMS - if true, output in degrees, minutes, seconds. Otherwise, output in degrees, minutes. -vars.text - text in the message -vars.displayTime - self explanatory -vars.msgFor - scope -]] - function mist.msgLL(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLLString{units = units, acc = acc, DMS = DMS} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - end - - --[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - vec3 ref point, maybe overload for vec2 as well? -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgBR(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString - local alt = vars.alt - local metric = vars.metric - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getBRString{units = units, ref = ref, alt = alt, metric = metric} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - end - - -- basically, just sub-types of mist.msgBR... saves folks the work of getting the ref point. - --[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - string red, blue -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgBullseye(vars) - if mist.DBs.missionData.bullseye[string.lower(vars.ref)] then - vars.ref = mist.DBs.missionData.bullseye[string.lower(vars.ref)] - mist.msgBR(vars) - end - end - - --[[ -vars.units- table of unit names (NOT unitNameTable- maybe this should change). -vars.ref - unit name of reference point -vars.alt - boolean, if used, includes altitude in string -vars.metric - boolean, gives distance in km instead of NM. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgBRA(vars) - if Unit.getByName(vars.ref) and Unit.getByName(vars.ref):isExist() == true then - vars.ref = Unit.getByName(vars.ref):getPosition().p - if not vars.alt then - vars.alt = true - end - mist.msgBR(vars) - end - end - - --[[ vars for mist.msgLeadingMGRS: -vars.units - table of unit names -vars.heading - direction -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number, 0 to 5. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgLeadingMGRS(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingMGRSString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc} - local newText - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - - end - - --[[ vars for mist.msgLeadingLL: -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.acc - number of digits after decimal point (can be negative) -vars.DMS - boolean, true if you want DMS. (optional) -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgLeadingLL(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local acc = vars.acc - local DMS = vars.DMS - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingLLString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, acc = acc, DMS = DMS} - local newText - - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - - end - - --[[ -vars.units - table of unit names -vars.heading - direction, number -vars.radius - number -vars.headingDegrees - boolean, switches heading to degrees (optional) -vars.metric - boolean, if true, use km instead of NM. (optional) -vars.alt - boolean, if true, include altitude. (optional) -vars.ref - vec3/vec2 reference point. -vars.text - text of the message -vars.displayTime -vars.msgFor - scope -]] - function mist.msgLeadingBR(vars) - local units = vars.units -- technically, I don't really need to do this, but it helps readability. - local heading = vars.heading - local radius = vars.radius - local headingDegrees = vars.headingDegrees - local metric = vars.metric - local alt = vars.alt - local ref = vars.ref -- vec2/vec3 will be handled in mist.getBRString - local text = vars.text - local displayTime = vars.displayTime - local msgFor = vars.msgFor - - local s = mist.getLeadingBRString{units = units, heading = heading, radius = radius, headingDegrees = headingDegrees, metric = metric, alt = alt, ref = ref} - local newText - - if text then - if string.find(text, '%%s') then -- look for %s - newText = string.format(text, s) -- insert the coordinates into the message - else - -- just append to the end. - newText = text .. s - end - else - newText = s - end - - mist.message.add{ - text = newText, - displayTime = displayTime, - msgFor = msgFor - } - end -end - ---- Demo functions. --- @section mist.demos -do -- mist.demos scope - mist.demos = {} - - function mist.demos.printFlightData(unit) - if unit:isExist() then - local function printData(unit, prevVel, prevE, prevTime) - local angles = mist.getAttitude(unit) - if angles then - local Heading = angles.Heading - local Pitch = angles.Pitch - local Roll = angles.Roll - local Yaw = angles.Yaw - local AoA = angles.AoA - local ClimbAngle = angles.ClimbAngle - - if not Heading then - Heading = 'NA' - else - Heading = string.format('%12.2f', mist.utils.toDegree(Heading)) - end - - if not Pitch then - Pitch = 'NA' - else - Pitch = string.format('%12.2f', mist.utils.toDegree(Pitch)) - end - - if not Roll then - Roll = 'NA' - else - Roll = string.format('%12.2f', mist.utils.toDegree(Roll)) - end - - local AoAplusYaw = 'NA' - if AoA and Yaw then - AoAplusYaw = string.format('%12.2f', mist.utils.toDegree((AoA^2 + Yaw^2)^0.5)) - end - - if not Yaw then - Yaw = 'NA' - else - Yaw = string.format('%12.2f', mist.utils.toDegree(Yaw)) - end - - if not AoA then - AoA = 'NA' - else - AoA = string.format('%12.2f', mist.utils.toDegree(AoA)) - end - - if not ClimbAngle then - ClimbAngle = 'NA' - else - ClimbAngle = string.format('%12.2f', mist.utils.toDegree(ClimbAngle)) - end - local unitPos = unit:getPosition() - local unitVel = unit:getVelocity() - local curTime = timer.getTime() - local absVel = string.format('%12.2f', mist.vec.mag(unitVel)) - - - local unitAcc = 'NA' - local Gs = 'NA' - local axialGs = 'NA' - local transGs = 'NA' - if prevVel and prevTime then - local xAcc = (unitVel.x - prevVel.x)/(curTime - prevTime) - local yAcc = (unitVel.y - prevVel.y)/(curTime - prevTime) - local zAcc = (unitVel.z - prevVel.z)/(curTime - prevTime) - - unitAcc = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc, z = zAcc})) - Gs = string.format('%12.2f', mist.vec.mag({x = xAcc, y = yAcc + 9.81, z = zAcc})/9.81) - axialGs = string.format('%12.2f', mist.vec.dp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x)/9.81) - transGs = string.format('%12.2f', mist.vec.mag(mist.vec.cp({x = xAcc, y = yAcc + 9.81, z = zAcc}, unitPos.x))/9.81) - end - - local E = 0.5*mist.vec.mag(unitVel)^2 + 9.81*unitPos.p.y - - local energy = string.format('%12.2e', E) - - local dEdt = 'NA' - if prevE and prevTime then - dEdt = string.format('%12.2e', (E - prevE)/(curTime - prevTime)) - end - - trigger.action.outText(string.format('%-25s', 'Heading: ') .. Heading .. ' degrees\n' .. string.format('%-25s', 'Roll: ') .. Roll .. ' degrees\n' .. string.format('%-25s', 'Pitch: ') .. Pitch - .. ' degrees\n' .. string.format('%-25s', 'Yaw: ') .. Yaw .. ' degrees\n' .. string.format('%-25s', 'AoA: ') .. AoA .. ' degrees\n' .. string.format('%-25s', 'AoA plus Yaw: ') .. AoAplusYaw .. ' degrees\n' .. string.format('%-25s', 'Climb Angle: ') .. - ClimbAngle .. ' degrees\n' .. string.format('%-25s', 'Absolute Velocity: ') .. absVel .. ' m/s\n' .. string.format('%-25s', 'Absolute Acceleration: ') .. unitAcc ..' m/s^2\n' - .. string.format('%-25s', 'Axial G loading: ') .. axialGs .. ' g\n' .. string.format('%-25s', 'Transverse G loading: ') .. transGs .. ' g\n' .. string.format('%-25s', 'Absolute G loading: ') .. Gs .. ' g\n' .. string.format('%-25s', 'Energy: ') .. energy .. ' J/kg\n' .. string.format('%-25s', 'dE/dt: ') .. dEdt ..' J/(kg*s)', 1) - return unitVel, E, curTime - end - end - - local function frameFinder(unit, prevVel, prevE, prevTime) - if unit:isExist() then - local currVel = unit:getVelocity() - if prevVel and (prevVel.x ~= currVel.x or prevVel.y ~= currVel.y or prevVel.z ~= currVel.z) or (prevTime and (timer.getTime() - prevTime) > 0.25) then - prevVel, prevE, prevTime = printData(unit, prevVel, prevE, prevTime) - end - mist.scheduleFunction(frameFinder, {unit, prevVel, prevE, prevTime}, timer.getTime() + 0.005) -- it can't go this fast, limited to the 100 times a sec check right now. - end - end - - - local curVel = unit:getVelocity() - local curTime = timer.getTime() - local curE = 0.5*mist.vec.mag(curVel)^2 + 9.81*unit:getPosition().p.y - frameFinder(unit, curVel, curE, curTime) - - end - - end - -end - - - -do - --[[ stuff for marker panels - marker.add() add marker. Point of these functions is to simplify process and to store all mark panels added. - -- generates Id if not specified or if multiple marks created. - -- makes marks for countries by creating a mark for each client group in the country - -- can create multiple marks if needed for groups and countries. - -- adds marks to table for parsing and removing - -- Uses similar structure as messages. Big differences is it doesn't only mark to groups. - If to All, then mark is for All - if to coa mark is to coa - if to specific units, mark is to group - - - -------- - STUFF TO Check - -------- - If mark added to a group before a client joins slot is synced. - Mark made for cliet A in Slot A. Client A leaves, Client B joins in slot A. What do they see? - - - May need to automate process... - - - Could release this. But things I might need to add/change before doing so. - - removing marks and re-adding in same sequence doesn't appear to work. May need to schedule adding mark if updating an entry. - - I really dont like the old message style code for which groups get the message. Perhaps change to unitsTable and create function for getting humanUnitsTable. - = Event Handler, and check it, for marks added via script or user to deconflict Ids. - - Full validation of passed values for a specific shape type. - - ]] - - local usedMarks = {} - - local mDefs = { - coa = { - ['red'] = {fillColor = {.8, 0 , 0, .5}, color = {.8, 0 , 0, .5}, lineType = 2, fontSize = 16}, - ['blue'] = {fillColor = {0, 0 , 0.8, .5}, color = {0, 0 , 0.8, .5}, lineType = 2, fontSize = 16}, - ['all'] = {fillColor = {.1, .1 , .1, .5}, color = {.9, .9 , .9, .5}, lineType = 2, fontSize = 16}, - ['neutral'] = {fillColor = {.1, .1 , .1, .5}, color = {.2, .2 , .2, .5}, lineType = 2, fontSize = 16}, - }, - } - - local userDefs = {['red'] = {},['blue'] = {},['all'] = {},['neutral'] = {}} - - local mId = 1000 - - local tNames = {'line', 'circle','rect', 'arrow', 'text', 'quad', 'freeform'} - local tLines = {[0] = 'no line', [1] = 'solid', [2] = 'dashed',[3] = 'dotted', [4] = 'dot dash' ,[5] = 'long dash', [6] = 'two dash'} - local coas = {[-1] = 'all', [0] = 'neutral', [1] = 'red', [2] = 'blue'} - - local altNames = {['poly'] = 7, ['lines'] = 1, ['polygon'] = 7 } - - local function draw(s) - --log:warn(s) - if type(s) == 'table' then - local mType = s.markType - if mType == 'panel' then - if markScope == 'coa' then - trigger.action.markToCoalition(s.markId, s.text, s.pos, s.markFor, s.readOnly) - elseif markScope == 'group' then - trigger.action.markToGroup(s.markId, s.text, s.pos, s.markFor, s.readOnly) - else - trigger.action.markToAll(s.markId, s.text, s.pos, s.readOnly) - end - elseif mType == 'line' then - trigger.action.lineToAll(s.coa, s.markId, s.pos[1], s.pos[2], s.color, s.fillColor, s.lineType, s.readOnly, s.message) - elseif mType == 'circle' then - trigger.action.circleToAll(s.coa, s.markId, s.pos[1], s.radius, s.color, s.fillColor, s.lineType, s.readOnly, s.message) - elseif mType == 'rect' then - trigger.action.rectToAll(s.coa, s.markId, s.pos[1], s.pos[2], s.color, s.fillColor, s.lineType, s.readOnly, s.message) - elseif mType == 'arrow' then - trigger.action.arrowToAll(s.coa, s.markId, s.pos[1], s.pos[2], s.color, s.fillColor, s.lineType, s.readOnly, s.message) - elseif mType == 'text' then - trigger.action.textToAll(s.coa, s.markId, s.pos[1], s.color, s.fillColor, s.fontSize, s.readOnly, s.text) - elseif mType == 'quad' then - trigger.action.quadToAll(s.coa, s.markId, s.pos[1], s.pos[2], s.pos[3], s.pos[4], s.color, s.fillColor, s.lineType, s.readOnly, s.message) - end - if s.name and not usedMarks[s.name] then - usedMarks[s.name] = s.markId - end - elseif type(s) == 'string' then - --log:warn(s) - mist.utils.dostring(s) - end - end - - mist.marker = {} - - local function markSpamFilter(recList, spamBlockOn) - - for id, name in pairs(recList) do - if name == spamBlockOn then - --log:info('already on recList') - return recList - end - end - --log:info('add to recList') - table.insert(recList, spamBlockOn) - return recList - end - - local function iterate() - while mId < 10000000 do - if usedMarks[mId] then - mId = mId + 1 - else - return mist.utils.deepCopy(mId) - end - end - return mist.utils.deepCopy(mId) - end - - local function validateColor(val) - if type(val) == 'table' then - for i = 1, #val do - if type(val[i]) == 'number' and val[i] > 1 then - val[i] = val[i]/255 -- convert RGB values from 0-255 to 0-1 equivilent. - end - end - elseif type(val) == 'string' then - val = mist.utils.hexToRGB(val) - - end - return val - end - - local function checkDefs(vName, coa) - --log:warn('CheckDefs: $1 $2', vName, coa) - local coaName - if type(coa) == 'number' then - if coas[coa] then - coaName = coas[coa] - end - elseif type(coa) == 'string' then - coaName = coa - end - - -- log:warn(coaName) - if userDefs[coaName] and userDefs[coaName][vName] then - return userDefs[coaName][vName] - elseif mDefs.coa[coaName] and mDefs.coa[coaName][vName] then - return mDefs.coa[coaName][vName] - end - - end - - function mist.marker.getNextId() - return iterate() - end - - local handle = {} - function handle:onEvent(e) - if world.event.S_EVENT_MARK_ADDED == e.id and e.idx then - usedMarks[e.idx] = e.idx - if not mist.DBs.markList[e.idx] then - --log:info('create maker DB: $1', e.idx) - mist.DBs.markList[e.idx] = {time = e.time, pos = e.pos, groupId = e.groupId, mType = 'panel', text = e.text, markId = e.idx, coalition = e.coalition} - if e.unit then - mist.DBs.markList[e.idx].unit = e.initiaor:getName() - end - --log:info(mist.marker.list[e.idx]) - end - - elseif world.event.S_EVENT_MARK_CHANGE == e.id and e.idx then - if mist.DBs.markList[e.idx] then - mist.DBs.markList[e.idx].text = e.text - end - elseif world.event.S_EVENT_MARK_REMOVE == e.id and e.idx then - if mist.DBs.markList[e.idx] then - mist.DBs.markList[e.idx] = nil - end - end - - end - - local function getMarkId(id) - if mist.DBs.markList[id] then - return id - else - for mEntry, mData in pairs(mist.DBs.markList) do - if id == mData.name or id == mData.id then - return mData.id - end - end - end - - - end - - - local function removeMark(id) - --log:info("Removing Mark: $1", id - local removed = false - if type(id) == 'table' then - for ind, val in pairs(id) do - local r = getMarkId(val) - if r then - trigger.action.removeMark(r) - mist.DBs.markList[r] = nil - removed = true - end - end - - else - local r = getMarkId(id) - trigger.action.removeMark(r) - mist.DBs.markList[r] = nil - removed = true - end - return removed - end - - world.addEventHandler(handle) - function mist.marker.setDefault(vars) - local anyChange = false - if vars and type(vars) == 'table' then - for l1, l1Data in pairs(vars) do - if type(l1Data) == 'table' then - if not userDefs[l1] then - userDefs[l1] = {} - end - - for l2, l2Data in pairs(l1Data) do - userDefs[l1][l2] = l2Data - anyChange = true - end - else - userDefs[l1] = l1Data - anyChange = true - end - end - - end - return anyChange - end - - function mist.marker.add(vars) - --log:warn('markerFunc') - --log:warn(vars) - local pos = vars.point or vars.points or vars.pos - local text = vars.text or '' - local markFor = vars.markFor - local markForCoa = vars.markForCoa or vars.coa -- optional, can be used if you just want to mark to a specific coa/all - local id = vars.id or vars.markId or vars.markid - local mType = vars.mType or vars.markType or vars.type or 0 - local color = vars.color - local fillColor = vars.fillColor - local lineType = vars.lineType or 2 - local readOnly = vars.readOnly or true - local message = vars.message - local fontSize = vars.fontSize - local name = vars.name - local radius = vars.radius or 500 - - local coa = -1 - local usedId = 0 - - - - if id then - if type(id) ~= 'number' then - name = id - usedId = iterate() - end - --log:info('checkIfIdExist: $1', id) - --[[ - Maybe it should treat id or name as the same thing/single value. - - If passed number it will use that as the first Id used and will delete/update any marks associated with that same value. - - - ]] - - local lId = id or name - if mist.DBs.markList[id] then ---------- NEED A BETTER WAY TO ASSOCIATE THE ID VALUE. CUrrnetly deleting from table and checking if that deleted entry exists which it wont. - --log:warn('active mark to be removed: $1', id) - name = mist.DBs.markList[id].name or id - removeMark(id) - elseif usedMarks[id] then - --log:info('exists in usedMarks: $1', id) - removeMark(usedMarks[id]) - elseif name and usedMarks[name] then - --log:info('exists in usedMarks: $1', name) - removeMark(usedMarks[name]) - end - usedId = iterate() - usedMarks[id] = usedId -- redefine the value used - end - if name then - usedMarks[name] = usedId - end - - if usedId == 0 then - usedId = iterate() - end - if mType then - if type(mType) == 'string' then - for i = 1, #tNames do - --log:warn(tNames[i]) - if mist.stringMatch(mType, tNames[i]) then - mType = i - break - end - end - elseif type(mType) == 'number' and mType > #tNames then - mType = 0 - end - end - --log:warn(mType) - local markScope = 'all' - local markForTable = {} - - if pos then - if pos[1] then - for i = 1, #pos do - pos[i] = mist.utils.makeVec3(pos[i]) - end - - else - pos[1] = mist.utils.makeVec3(pos) - end - - end - if text and type(text) ~= string then - text = tostring(text) - end - - if markForCoa then - if type(markForCoa) == 'string' then - if tonumber(markForCoa) then - coa = coas[tonumber(markForCoa)] - markScope = 'coa' - else - for ind, cName in pairs(coas) do - if mist.stringMatch(cName, markForCoa) then - coa = ind - markScope = 'coa' - break - end - end - end - elseif type(markForCoa) == 'number' and markForCoa >=-1 and markForCoa <= #coas then - coa = markForCoa - markScore = 'coa' - end - - - - elseif markFor then - if type(markFor) == 'number' then -- groupId - if mist.DBs.groupsById[markFor] then - markScope = 'group' - end - elseif type(markFor) == 'string' then -- groupName - if mist.DBs.groupsByName[markFor] then - markScope = 'group' - markFor = mist.DBs.groupsByName[markFor].groupId - end - elseif type(markFor) == 'table' then -- multiple groupName, country, coalition, all - markScope = 'table' - --log:warn(markFor) - for forIndex, forData in pairs(markFor) do -- need to rethink this part and organization. Gotta be a more logical way to send messages to coa, groups, or all. - for list, listData in pairs(forData) do - --log:warn(listData) - forIndex = string.lower(forIndex) - if type(listData) == 'string' then - listData = string.lower(listData) - end - if listData == 'all' then - markScope = 'all' - break - elseif (forIndex == 'coa' or forIndex == 'ca') then -- mark for coa or CA. - local matches = 0 - for name, index in pairs (coalition.side) do - if listData == string.lower(name) then - markScope = 'coa' - markFor = index - coa = index - matches = matches + 1 - end - end - if matches > 1 then - markScope = 'all' - end - elseif forIndex == 'countries' then - for clienId, clientData in pairs(mist.DBs.humansById) do - if (string.lower(clientData.country) == listData) or (forIndex == 'units' and string.lower(clientData.unitName) == listData) then - markForTable = markSpamFilter(markForTable, clientData.groupId) - end - end - elseif forIndex == 'unittypes' then -- mark to group - -- iterate play units - for clientId, clientData in pairs(mist.DBs.humansById) do - for typeId, typeData in pairs(listData) do - --log:warn(typeData) - local found = false - if list == 'all' or clientData.coalition and type(clientData.coalition) == 'string' and mist.stringMatch(clientData.coalition, list) then - if mist.matchString(typeData, clientData.type) then - found = true - else - -- check other known names for aircraft - end - end - if found == true then - markForTable = markSpamFilter(markForTable, clientData.groupId) -- sends info to other function to see if client is already recieving the current message. - end - for clientDataEntry, clientDataVal in pairs(clientData) do - if type(clientDataVal) == 'string' then - - if mist.matchString(list, clientDataVal) == true or list == 'all' then - local sString = typeData - for rName, pTbl in pairs(typeBase) do -- just a quick check to see if the user may have meant something and got the specific type of the unit wrong - for pIndex, pName in pairs(pTbl) do - if mist.stringMatch(sString, pName) then - sString = rName - end - end - end - if mist.stringMatch(sString, clientData.type) then - found = true - markForTable = markSpamFilter(markForTable, clientData.groupId) -- sends info oto other function to see if client is already recieving the current message. - --table.insert(newMsgFor, clientId) - end - end - end - if found == true then -- shouldn't this be elsewhere too? - break - end - end - end - - end - end - end - end - end - else - markScope = 'all' - end - - if mType == 0 then - local data = {markId = usedId, text = text, pos = pos[1], markScope = markScope, markFor = markFor, markType = 'panel', name = name, time = timer.getTime()} - if markScope ~= 'table' then - -- create marks - - mist.DBs.markList[usedId] = data-- add to the DB - - else - if #markForTable > 0 then - --log:info('iterate') - local list = {} - if id and not name then - name = id - end - for i = 1, #markForTable do - local newId = iterate() - local data = {markId = newId, text = text, pos = pos[i], markFor = markForTable[i], markType = 'panel', name = name, readOnly = readOnly, time = timer.getTime()} - mist.DBs.markList[newId] = data - table.insert(list, data) - - draw(data) - - end - return list - end - end - - draw(data) - - return data - elseif mType > 0 then - local newId = iterate() - local fCal = {} - fCal[#fCal+1] = mType - fCal[#fCal+1] = coa - fCal[#fCal+1] = usedId - - local likeARainCoat = false - if mType == 7 then - local score = 0 - for i = 1, #pos do - if i < #pos then - local val = ((pos[i+1].x - pos[i].x)*(pos[i+1].z + pos[i].z)) - --log:warn("$1 index score is: $2", i, val) - score = score + val - else - score = score + ((pos[1].x - pos[i].x)*(pos[1].z + pos[i].z)) - end - end - --log:warn(score) - if score > 0 then -- it is anti-clockwise. Due to DCS bug make it clockwise. - likeARainCoat = true - --log:warn('flip') - - for i = #pos, 1, -1 do - fCal[#fCal+1] = pos[i] - end - end - end - if likeARainCoat == false then - for i = 1, #pos do - fCal[#fCal+1] = pos[i] - end - end - if radius and mType == 2 then - fCal[#fCal+1] = radius - end - - if not color then - color = checkDefs('color', coa) - else - color = validateColor(color) - end - fCal[#fCal+1] = color - - - if not fillColor then - fillColor = checkDefs('fillColor', coa) - else - fillColor = validateColor(fillColor) - end - fCal[#fCal+1] = fillColor - - if mType == 5 then -- text to all - if not fontSize then - fontSize = checkDefs('fontSize', coa) or 16 - end - fCal[#fCal+1] = fontSize - else - if not lineType then - lineType = checkDefs('lineType', coa) or 2 - end - end - fCal[#fCal+1] = lineType - if not readOnly then - readOnly = true - end - fCal[#fCal+1] = readOnly - if mType == 5 then - fCal[#fCal+1] = text - else - - fCal[#fCal+1] = message - end - local data = {coa = coa, markId = usedId, pos = pos, markFor = markFor, color = color, readOnly = readOnly, message = message, fillColor = fillColor, lineType = lineType, markType = tNames[mType], name = name, radius = radius, text = text, fontSize = fontSize, time = timer.getTime()} - mist.DBs.markList[usedId] = data - - if mType == 7 or mType == 1 then - local s = "trigger.action.markupToAll(" - - for i = 1, #fCal do - --log:warn(fCal[i]) - if type(fCal[i]) == 'table' or type(fCal[i]) == 'boolean' then - s = s .. mist.utils.oneLineSerialize(fCal[i]) - else - s = s .. fCal[i] - end - if i < #fCal then - s = s .. ',' - end - end - - s = s .. ')' - if name then - usedMarks[name] = usedId - end - draw(s) - - else - - draw(data) - - end - return data - end - - - end - - function mist.marker.remove(id) - return removeMark(id) - end - - function mist.marker.get(id) - if mist.DBs.markList[id] then - return mist.DBs.markList[id] - end - local names = {} - for markId, data in pairs(mist.DBs.markList) do - if data.name and data.name == id then - table.insert(names, data) - end - end - if #names >= 1 then - return names - end - end - - function mist.marker.drawZone(name, v) - if mist.DBs.zonesByName[name] then - --log:warn(mist.DBs.zonesByName[name]) - local vars = v or {} - local ref = mist.utils.deepCopy(mist.DBs.zonesByName[name]) - - if ref.type == 2 then -- it is a quad, but use freeform cause it isnt as bugged - vars.mType = 6 - vars.point = ref.verticies - else - vars.mType = 2 - vars.radius = ref.radius - vars.point = ref.point - end - - - if not (vars.ignoreColor and vars.ignoreColor == true) and not vars.fillColor then - vars.fillColor = ref.color - end - - --log:warn(vars) - return mist.marker.add(vars) - end - end - - function mist.marker.drawShape(name, v) - if mist.DBs.drawingByName[name] then - - local d = v or {} - local o = mist.utils.deepCopy(mist.DBs.drawingByName[name]) - --mist.marker.add({point = {x = o.mapX, z = o.mapY}, text = name}) - --log:warn(o) - d.points = o.points or {} - if o.primitiveType == "Polygon" then - d.mType = 7 - - if o.polygonMode == "rect" then - d.mType = 6 - elseif o.polygonMode == "circle" then - d.mType = 2 - d.points = {x = o.mapX, y = o.mapY} - d.radius = o.radius - end - elseif o.primitiveType == "TextBox" then - d.mType = 5 - d.points = {x = o.mapX, y = o.mapY} - d.text = o.text or d.text - d.fontSize = d.fontSize or o.fontSize - end - -- NOTE TO SELF. FIGURE OUT WHICH SHAPES NEED TO BE OFFSET. OVAL YES. - - if o.fillColorString and not d.fillColor then - d.fillColor = mist.utils.hexToRGB(o.fillColorString) - end - if o.colorString then - d.color = mist.utils.hexToRGB(o.colorString) - end - - - if o.thickness == 0 then - d.lineType = 0 - elseif o.style == 'solid' then - d.lineType = 1 - elseif o.style == 'dot' then - d.lineType = 2 - elseif o.style == 'dash' then - d.lineType = 3 - else - d.lineType = 1 - end - - - if o.primitiveType == "Line" and #d.points >= 2 then - d.mType = 1 - local rtn = {} - for i = 1, #d.points -1 do - local var = mist.utils.deepCopy(d) - var.points = {} - var.points[1] = d.points[i] - var.points[2] = d.points[i+1] - table.insert(rtn, mist.marker.add(var)) - end - return rtn - else - if d.mType then - --log:warn(d) - return mist.marker.add(d) - end - end - end - - - end - - - --[[ - function mist.marker.circle(v) - - - end -]] -end ---- Time conversion functions. --- @section mist.time -do -- mist.time scope - mist.time = {} - -- returns a string for specified military time - -- theTime is optional - -- if present current time in mil time is returned - -- if number or table the time is converted into mil tim - function mist.time.convertToSec(timeTable) - - local timeInSec = 0 - if timeTable and type(timeTable) == 'number' then - timeInSec = timeTable - elseif timeTable and type(timeTable) == 'table' and (timeTable.d or timeTable.h or timeTable.m or timeTable.s) then - if timeTable.d and type(timeTable.d) == 'number' then - timeInSec = timeInSec + (timeTable.d*86400) - end - if timeTable.h and type(timeTable.h) == 'number' then - timeInSec = timeInSec + (timeTable.h*3600) - end - if timeTable.m and type(timeTable.m) == 'number' then - timeInSec = timeInSec + (timeTable.m*60) - end - if timeTable.s and type(timeTable.s) == 'number' then - timeInSec = timeInSec + timeTable.s - end - - end - return timeInSec - end - - function mist.time.getDHMS(timeInSec) - if timeInSec and type(timeInSec) == 'number' then - local tbl = {d = 0, h = 0, m = 0, s = 0} - if timeInSec > 86400 then - while timeInSec > 86400 do - tbl.d = tbl.d + 1 - timeInSec = timeInSec - 86400 - end - end - if timeInSec > 3600 then - while timeInSec > 3600 do - tbl.h = tbl.h + 1 - timeInSec = timeInSec - 3600 - end - end - if timeInSec > 60 then - while timeInSec > 60 do - tbl.m = tbl.m + 1 - timeInSec = timeInSec - 60 - end - end - tbl.s = timeInSec - return tbl - else - log:error("Didn't recieve number") - return - end - end - - function mist.getMilString(theTime) - local timeInSec = 0 - if theTime then - timeInSec = mist.time.convertToSec(theTime) - else - timeInSec = mist.utils.round(timer.getAbsTime(), 0) - end - - local DHMS = mist.time.getDHMS(timeInSec) - - return tostring(string.format('%02d', DHMS.h) .. string.format('%02d',DHMS.m)) - end - - function mist.getClockString(theTime, hour) - local timeInSec = 0 - if theTime then - timeInSec = mist.time.convertToSec(theTime) - else - timeInSec = mist.utils.round(timer.getAbsTime(), 0) - end - local DHMS = mist.time.getDHMS(timeInSec) - if hour then - if DHMS.h > 12 then - DHMS.h = DHMS.h - 12 - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' PM') - else - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s) .. ' AM') - end - else - return tostring(string.format('%02d', DHMS.h) .. ':' .. string.format('%02d',DHMS.m) .. ':' .. string.format('%02d',DHMS.s)) - end - end - - -- returns the date in string format - -- both variables optional - -- first val returns with the month as a string - -- 2nd val defins if it should be written the American way or the wrong way. - function mist.time.getDate(convert) - local cal = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} -- - local date = {} - - if not env.mission.date then -- Not likely to happen. Resaving mission auto updates this to remove it. - date.d = 0 - date.m = 6 - date.y = 2011 - else - date.d = env.mission.date.Day - date.m = env.mission.date.Month - date.y = env.mission.date.Year - end - local start = 86400 - local timeInSec = mist.utils.round(timer.getAbsTime()) - if convert and type(convert) == 'number' then - timeInSec = convert - end - if timeInSec > 86400 then - while start < timeInSec do - if date.d >= cal[date.m] then - if date.m == 2 and date.d == 28 then -- HOLY COW we can edit years now. Gotta re-add this! - if date.y % 4 == 0 and date.y % 100 == 0 and date.y % 400 ~= 0 or date.y % 4 > 0 then - date.m = date.m + 1 - date.d = 0 - end - --date.d = 29 - else - date.m = date.m + 1 - date.d = 0 - end - end - if date.m == 13 then - date.m = 1 - date.y = date.y + 1 - end - date.d = date.d + 1 - start = start + 86400 - - end - end - return date - end - - function mist.time.relativeToStart(time) - if type(time) == 'number' then - return time - timer.getTime0() - end - end - - function mist.getDateString(rtnType, murica, oTime) -- returns date based on time - local word = {'January', 'Feburary', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' } -- 'etc - local curTime = 0 - if oTime then - curTime = oTime - else - curTime = mist.utils.round(timer.getAbsTime()) - end - local tbl = mist.time.getDate(curTime) - - if rtnType then - if murica then - return tostring(word[tbl.m] .. ' ' .. tbl.d .. ' ' .. tbl.y) - else - return tostring(tbl.d .. ' ' .. word[tbl.m] .. ' ' .. tbl.y) - end - else - if murica then - return tostring(tbl.m .. '.' .. tbl.d .. '.' .. tbl.y) - else - return tostring(tbl.d .. '.' .. tbl.m .. '.' .. tbl.y) - end - end - end - --WIP - function mist.time.milToGame(milString, rtnType) --converts a military time. By default returns the abosolute time that event would occur. With optional value it returns how many seconds from time of call till that time. - local curTime = mist.utils.round(timer.getAbsTime()) - local milTimeInSec = 0 - - if milString and type(milString) == 'string' and string.len(milString) >= 4 then - local hr = tonumber(string.sub(milString, 1, 2)) - local mi = tonumber(string.sub(milString, 3)) - milTimeInSec = milTimeInSec + (mi*60) + (hr*3600) - elseif milString and type(milString) == 'table' and (milString.d or milString.h or milString.m or milString.s) then - milTimeInSec = mist.time.convertToSec(milString) - end - - local startTime = timer.getTime0() - local daysOffset = 0 - if startTime > 86400 then - daysOffset = mist.utils.round(startTime/86400) - if daysOffset > 0 then - milTimeInSec = milTimeInSec *daysOffset - end - end - - if curTime > milTimeInSec then - milTimeInSec = milTimeInSec + 86400 - end - if rtnType then - milTimeInSec = milTimeInSec - startTime - end - return milTimeInSec - end - - -end - ---- Group task functions. --- @section tasks -do -- group tasks scope - mist.ground = {} - mist.fixedWing = {} - mist.heli = {} - mist.air = {} - mist.air.fixedWing = {} - mist.air.heli = {} - mist.ship = {} - - --- Tasks group to follow a route. - -- This sets the mission task for the given group. - -- Any wrapped actions inside the path (like enroute - -- tasks) will be executed. - -- @tparam Group group group to task. - -- @tparam table path containing - -- points defining a route. - function mist.goRoute(group, path) - local misTask = { - id = 'Mission', - params = { - route = { - points = mist.utils.deepCopy(path), - }, - }, - } - if type(group) == 'string' then - group = Group.getByName(group) - end - if group then - local groupCon = group:getController() - if groupCon then - --log:warn(misTask) - groupCon:setTask(misTask) - return true - end - end - return false - end - - -- same as getGroupPoints but returns speed and formation type along with vec2 of point} - function mist.getGroupRoute(groupIdent, task) - -- refactor to search by groupId and allow groupId and groupName as inputs - local gpId = groupIdent - if mist.DBs.MEgroupsByName[groupIdent] then - gpId = mist.DBs.MEgroupsByName[groupIdent].groupId - else - log:error('$1 not found in mist.DBs.MEgroupsByName', groupIdent) - end - - for coa_name, coa_data in pairs(env.mission.coalition) do - if type(coa_data) == 'table' then - if coa_data.country then --there is a country table - for cntry_id, cntry_data in pairs(coa_data.country) do - for obj_cat_name, obj_cat_data in pairs(cntry_data) do - if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" then -- only these types have points - if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then --there's a group! - for group_num, group_data in pairs(obj_cat_data.group) do - if group_data and group_data.groupId == gpId then -- this is the group we are looking for - if group_data.route and group_data.route.points and #group_data.route.points > 0 then - local points = {} - - for point_num, point in pairs(group_data.route.points) do - local routeData = {} - if env.mission.version > 7 and env.mission.version < 19 then - routeData.name = env.getValueDictByKey(point.name) - else - routeData.name = point.name - end - if not point.point then - routeData.x = point.x - routeData.y = point.y - else - routeData.point = point.point --it's possible that the ME could move to the point = Vec2 notation. - end - routeData.form = point.action - routeData.speed = point.speed - routeData.alt = point.alt - routeData.alt_type = point.alt_type - routeData.airdromeId = point.airdromeId - routeData.helipadId = point.helipadId - routeData.type = point.type - routeData.action = point.action - if task then - routeData.task = point.task - end - points[point_num] = routeData - end - - return points - end - log:error('Group route not defined in mission editor for groupId: $1', gpId) - return - end --if group_data and group_data.name and group_data.name == 'groupname' - end --for group_num, group_data in pairs(obj_cat_data.group) do - end --if ((type(obj_cat_data) == 'table') and obj_cat_data.group and (type(obj_cat_data.group) == 'table') and (#obj_cat_data.group > 0)) then - end --if obj_cat_name == "helicopter" or obj_cat_name == "ship" or obj_cat_name == "plane" or obj_cat_name == "vehicle" or obj_cat_name == "static" then - end --for obj_cat_name, obj_cat_data in pairs(cntry_data) do - end --for cntry_id, cntry_data in pairs(coa_data.country) do - end --if coa_data.country then --there is a country table - end --if coa_name == 'red' or coa_name == 'blue' and type(coa_data) == 'table' then - end --for coa_name, coa_data in pairs(mission.coalition) do - end - - -- function mist.ground.buildPath() end -- ???? - - function mist.ground.patrolRoute(vars) - --log:info('patrol') - local tempRoute = {} - local useRoute = {} - local gpData = vars.gpData - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - local useGroupRoute - if not vars.useGroupRoute then - useGroupRoute = vars.gpData - else - useGroupRoute = vars.useGroupRoute - end - local routeProvided = false - if not vars.route then - if useGroupRoute then - tempRoute = mist.getGroupRoute(useGroupRoute) - end - else - useRoute = vars.route - local posStart = mist.getLeadPos(gpData) - useRoute[1] = mist.ground.buildWP(posStart, useRoute[1].action, useRoute[1].speed) - routeProvided = true - end - - - local overRideSpeed = vars.speed or 'default' - local pType = vars.pType - local offRoadForm = vars.offRoadForm or 'default' - local onRoadForm = vars.onRoadForm or 'default' - - if routeProvided == false and #tempRoute > 0 then - local posStart = mist.getLeadPos(gpData) - - - useRoute[#useRoute + 1] = mist.ground.buildWP(posStart, offRoadForm, overRideSpeed) - for i = 1, #tempRoute do - local tempForm = tempRoute[i].action - local tempSpeed = tempRoute[i].speed - - if offRoadForm == 'default' then - tempForm = tempRoute[i].action - end - if onRoadForm == 'default' then - onRoadForm = 'On Road' - end - if (string.lower(tempRoute[i].action) == 'on road' or string.lower(tempRoute[i].action) == 'onroad' or string.lower(tempRoute[i].action) == 'on_road') then - tempForm = onRoadForm - else - tempForm = offRoadForm - end - - if type(overRideSpeed) == 'number' then - tempSpeed = overRideSpeed - end - - - useRoute[#useRoute + 1] = mist.ground.buildWP(tempRoute[i], tempForm, tempSpeed) - end - - if pType and string.lower(pType) == 'doubleback' then - local curRoute = mist.utils.deepCopy(useRoute) - for i = #curRoute, 2, -1 do - useRoute[#useRoute + 1] = mist.ground.buildWP(curRoute[i], curRoute[i].action, curRoute[i].speed) - end - end - - useRoute[1].action = useRoute[#useRoute].action -- make it so the first WP matches the last WP - end - - local cTask3 = {} - local newPatrol = {} - newPatrol.route = useRoute - newPatrol.gpData = gpData:getName() - cTask3[#cTask3 + 1] = 'mist.ground.patrolRoute(' - cTask3[#cTask3 + 1] = mist.utils.oneLineSerialize(newPatrol) - cTask3[#cTask3 + 1] = ')' - cTask3 = table.concat(cTask3) - local tempTask = { - id = 'WrappedAction', - params = { - action = { - id = 'Script', - params = { - command = cTask3, - - }, - }, - }, - } - - useRoute[#useRoute].task = tempTask - log:info(useRoute) - mist.goRoute(gpData, useRoute) - - return - end - - function mist.ground.patrol(gpData, pType, form, speed) - local vars = {} - - if type(gpData) == 'table' and gpData:getName() then - gpData = gpData:getName() - end - - vars.useGroupRoute = gpData - vars.gpData = gpData - vars.pType = pType - vars.offRoadForm = form - vars.speed = speed - - mist.ground.patrolRoute(vars) - - return - end - - -- No longer accepts path - function mist.ground.buildWP(point, overRideForm, overRideSpeed) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - local form, speed - - if point.speed and not overRideSpeed then - wp.speed = point.speed - elseif type(overRideSpeed) == 'number' then - wp.speed = overRideSpeed - else - wp.speed = mist.utils.kmphToMps(20) - end - - if point.form and not overRideForm then - form = point.form - else - form = overRideForm - end - - if not form then - wp.action = 'Cone' - else - form = string.lower(form) - if form == 'off_road' or form == 'off road' then - wp.action = 'Off Road' - elseif form == 'on_road' or form == 'on road' then - wp.action = 'On Road' - elseif form == 'rank' or form == 'line_abrest' or form == 'line abrest' or form == 'lineabrest'then - wp.action = 'Rank' - elseif form == 'cone' then - wp.action = 'Cone' - elseif form == 'diamond' then - wp.action = 'Diamond' - elseif form == 'vee' then - wp.action = 'Vee' - elseif form == 'echelon_left' or form == 'echelon left' or form == 'echelonl' then - wp.action = 'EchelonL' - elseif form == 'echelon_right' or form == 'echelon right' or form == 'echelonr' then - wp.action = 'EchelonR' - else - wp.action = 'Cone' -- if nothing matched - end - end - - wp.type = 'Turning Point' - - return wp - - end - - function mist.fixedWing.buildWP(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 2000 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or altType == 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or altType == 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = mist.utils.kmphToMps(500) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp - end - - function mist.heli.buildWP(point, WPtype, speed, alt, altType) - - local wp = {} - wp.x = point.x - - if point.z then - wp.y = point.z - else - wp.y = point.y - end - - if alt and type(alt) == 'number' then - wp.alt = alt - else - wp.alt = 500 - end - - if altType then - altType = string.lower(altType) - if altType == 'radio' or altType == 'agl' then - wp.alt_type = 'RADIO' - elseif altType == 'baro' or altType == 'asl' then - wp.alt_type = 'BARO' - end - else - wp.alt_type = 'RADIO' - end - - if point.speed then - speed = point.speed - end - - if point.type then - WPtype = point.type - end - - if not speed then - wp.speed = mist.utils.kmphToMps(200) - else - wp.speed = speed - end - - if not WPtype then - wp.action = 'Turning Point' - else - WPtype = string.lower(WPtype) - if WPtype == 'flyover' or WPtype == 'fly over' or WPtype == 'fly_over' then - wp.action = 'Fly Over Point' - elseif WPtype == 'turningpoint' or WPtype == 'turning point' or WPtype == 'turning_point' then - wp.action = 'Turning Point' - else - wp.action = 'Turning Point' - end - end - - wp.type = 'Turning Point' - return wp - end - - -- need to return a Vec3 or Vec2? - function mist.getRandPointInCircle(p, r, innerRadius, maxA, minA) - local point = mist.utils.makeVec3(p) - local theta = 2*math.pi*math.random() - local radius = r or 1000 - local minR = innerRadius or 0 - if maxA and not minA then - theta = math.rad(math.random(0, maxA - math.random())) - elseif maxA and minA then - if minA < maxA then - theta = math.rad(math.random(minA, maxA) - math.random()) - else - theta = math.rad(math.random(maxA, minA) - math.random()) - end - end - local rad = math.random() + math.random() - if rad > 1 then - rad = 2 - rad - end - - local radMult - if minR and minR <= radius then - --radMult = (radius - innerRadius)*rad + innerRadius - radMult = radius * math.sqrt((minR^2 + (radius^2 - minR^2) * math.random()) / radius^2) - else - radMult = radius*rad - end - - local rndCoord - if radius > 0 then - rndCoord = {x = math.cos(theta)*radMult + point.x, y = math.sin(theta)*radMult + point.z} - else - rndCoord = {x = point.x, y = point.z} - end - return rndCoord - end - - function mist.getRandomPointInZone(zoneName, innerRadius, maxA, minA) - if type(zoneName) == 'string' then - local zone = mist.DBs.zonesByName[zoneName] - if zone.type and zone.type == 2 then - return mist.getRandomPointInPoly(zone.verticies) - else - return mist.getRandPointInCircle(zone.point, zone.radius, innerRadius, maxA, minA) - end - end - return false - end - - function mist.getRandomPointInPoly(zone) - --env.info('Zone Size: '.. #zone) - local avg = mist.getAvgPoint(zone) - --log:warn(avg) - local radius = 0 - local minR = math.huge - local newCoord = {} - for i = 1, #zone do - if mist.utils.get2DDist(avg, zone[i]) > radius then - radius = mist.utils.get2DDist(avg, zone[i]) - end - if mist.utils.get2DDist(avg, zone[i]) < minR then - minR = mist.utils.get2DDist(avg, zone[i]) - end - end - --log:warn('Radius: $1', radius) - --log:warn('minR: $1', minR) - local lSpawnPos = {} - for j = 1, 100 do - newCoord = mist.getRandPointInCircle(avg, radius) - if mist.pointInPolygon(newCoord, zone) then - break - end - if j == 100 then - newCoord = mist.getRandPointInCircle(avg, 50000) - log:warn("Failed to find point in poly; Giving random point from center of the poly") - end - end - return newCoord - end - - function mist.getWindBearingAndVel(p) - local point = mist.utils.makeVec3(o) - local gLevel = land.getHeight({x = point.x, y = point.z}) - if point.y <= gLevel then - point.y = gLevel + 10 - end - local t = atmosphere.getWind(point) - local bearing = math.tan(t.z/t.x) - local vel = math.sqrt(t.x^2 + t.z^2) - return bearing, vel - - end - - function mist.groupToRandomPoint(vars) - local group = vars.group --Required - local point = vars.point --required - local radius = vars.radius or 0 - local innerRadius = vars.innerRadius - local form = vars.form or 'Cone' - local heading = vars.heading or math.random()*2*math.pi - local headingDegrees = vars.headingDegrees - local speed = vars.speed or mist.utils.kmphToMps(20) - - - local useRoads - if not vars.disableRoads then - useRoads = true - else - useRoads = false - end - - local path = {} - - if headingDegrees then - heading = headingDegrees*math.pi/180 - end - - if heading >= 2*math.pi then - heading = heading - 2*math.pi - end - - local rndCoord = mist.getRandPointInCircle(point, radius, innerRadius) - - local offset = {} - local posStart = mist.getLeadPos(group) - if posStart then - offset.x = mist.utils.round(math.sin(heading - (math.pi/2)) * 50 + rndCoord.x, 3) - offset.z = mist.utils.round(math.cos(heading + (math.pi/2)) * 50 + rndCoord.y, 3) - path[#path + 1] = mist.ground.buildWP(posStart, form, speed) - - - if useRoads == true and ((point.x - posStart.x)^2 + (point.z - posStart.z)^2)^0.5 > radius * 1.3 then - path[#path + 1] = mist.ground.buildWP({x = posStart.x + 11, z = posStart.z + 11}, 'off_road', speed) - path[#path + 1] = mist.ground.buildWP(posStart, 'on_road', speed) - path[#path + 1] = mist.ground.buildWP(offset, 'on_road', speed) - else - path[#path + 1] = mist.ground.buildWP({x = posStart.x + 25, z = posStart.z + 25}, form, speed) - end - end - path[#path + 1] = mist.ground.buildWP(offset, form, speed) - path[#path + 1] = mist.ground.buildWP(rndCoord, form, speed) - - mist.goRoute(group, path) - - return - end - - function mist.groupRandomDistSelf(gpData, dist, form, heading, speed, disableRoads) - local pos = mist.getLeadPos(gpData) - local fakeZone = {} - fakeZone.radius = dist or math.random(300, 1000) - fakeZone.point = {x = pos.x, y = pos.y, z = pos.z} - mist.groupToRandomZone(gpData, fakeZone, form, heading, speed, disableRoads) - - return - end - - function mist.groupToRandomZone(gpData, zone, form, heading, speed, disableRoads) - if type(gpData) == 'string' then - gpData = Group.getByName(gpData) - end - - if type(zone) == 'string' then - zone = mist.DBs.zonesByName[zone] - elseif type(zone) == 'table' and not zone.radius then - zone = mist.DBs.zonesByName[zone[math.random(1, #zone)]] - end - - if speed then - speed = mist.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.radius = zone.radius - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.point = mist.utils.zoneToVec3(zone) - vars.disableRoads = disableRoads - mist.groupToRandomPoint(vars) - - return - end - - function mist.isTerrainValid(coord, terrainTypes) -- vec2/3 and enum or table of acceptable terrain types - if coord.z then - coord.y = coord.z - end - local typeConverted = {} - - if type(terrainTypes) == 'string' then -- if its a string it does this check - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(terrainTypes) or string.lower(constData) == string.lower(terrainTypes) then - table.insert(typeConverted, constId) - end - end - elseif type(terrainTypes) == 'table' then -- if its a table it does this check - for typeId, typeData in pairs(terrainTypes) do - for constId, constData in pairs(land.SurfaceType) do - if string.lower(constId) == string.lower(typeData) or string.lower(constData) == string.lower(typeData) then - table.insert(typeConverted, constId) - end - end - end - end - for validIndex, validData in pairs(typeConverted) do - if land.getSurfaceType(coord) == land.SurfaceType[validData] then - log:info('Surface is : $1', validData) - return true - end - end - return false - end - - function mist.terrainHeightDiff(coord, searchSize) - local samples = {} - local searchRadius = 5 - if searchSize then - searchRadius = searchSize - end - if type(coord) == 'string' then - coord = mist.utils.zoneToVec3(coord) - end - - coord = mist.utils.makeVec2(coord) - - samples[#samples + 1] = land.getHeight(coord) - for i = 0, 360, 30 do - samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*searchRadius)), y = (coord.y + (math.cos(math.rad(i))*searchRadius))}) - if searchRadius >= 20 then -- if search radius is sorta large, take a sample halfway between center and outer edge - samples[#samples + 1] = land.getHeight({x = (coord.x + (math.sin(math.rad(i))*(searchRadius/2))), y = (coord.y + (math.cos(math.rad(i))*(searchRadius/2)))}) - end - end - local tMax, tMin = 0, 1000000 - for index, height in pairs(samples) do - if height > tMax then - tMax = height - end - if height < tMin then - tMin = height - end - end - return mist.utils.round(tMax - tMin, 2) - end - - function mist.groupToPoint(gpData, point, form, heading, speed, useRoads) - if type(point) == 'string' then - point = mist.DBs.zonesByName[point] - end - if speed then - speed = mist.utils.kmphToMps(speed) - end - - local vars = {} - vars.group = gpData - vars.form = form - vars.headingDegrees = heading - vars.speed = speed - vars.disableRoads = useRoads - vars.point = mist.utils.zoneToVec3(point) - mist.groupToRandomPoint(vars) - - return - end - - function mist.getLeadPos(group) - if type(group) == 'string' then -- group name - group = Group.getByName(group) - end - - local units = group:getUnits() - - local leader = units[1] - if Unit.getLife(leader) == 0 or not Unit.isExist(leader) then -- SHOULD be good, but if there is a bug, this code future-proofs it then. - local lowestInd = math.huge - for ind, unit in pairs(units) do - if Unit.isExist(unit) and ind < lowestInd then - lowestInd = ind - return unit:getPosition().p - end - end - end - if leader and Unit.isExist(leader) then -- maybe a little too paranoid now... - return leader:getPosition().p - end - end - - function mist.groupIsDead(groupName) -- copy more or less from on station - if Group.getByName(groupName) then - local gp = Group.getByName(groupName) - if #gp:getUnits() > 0 or gp:isExist() == true then - return false - end - end - return true - end - -end - ---- Database tables. --- @section mist.DBs - ---- Mission data --- @table mist.DBs.missionData --- @field startTime mission start time --- @field theatre mission theatre/map e.g. Caucasus --- @field version mission version --- @field files mission resources - ---- Tables used as parameters. --- @section varTables - ---- mist.flagFunc.units_in_polygon parameter table. --- @table unitsInPolygonVars --- @tfield table unit name table @{UnitNameTable}. --- @tfield table zone table defining a polygon. --- @tfield number|string flag flag to set to true. --- @tfield[opt] number|string stopflag if set to true the function --- will stop evaluating. --- @tfield[opt] number maxalt maximum altitude (MSL) for the --- polygon. --- @tfield[opt] number req_num minimum number of units that have --- to be in the polygon. --- @tfield[opt] number interval sets the interval for --- checking if units are inside of the polygon in seconds. Default: 1. --- @tfield[opt] boolean toggle switch the flag to false if required --- conditions are not met. Default: false. --- @tfield[opt] table unitTableDef ---- Logger class. --- @type mist.Logger -do -- mist.Logger scope - mist.Logger = {} - - --- parses text and substitutes keywords with values from given array. - -- @param text string containing keywords to substitute with values - -- or a variable. - -- @param ... variables to use for substitution in string. - -- @treturn string new string with keywords substituted or - -- value of variable as string. - local function formatText(text, ...) - if type(text) ~= 'string' then - if type(text) == 'table' then - text = mist.utils.oneLineSerialize(text) - else - text = tostring(text) - end - else - for index,value in ipairs(arg) do - -- TODO: check for getmetatabel(value).__tostring - if type(value) == 'table' then - value = mist.utils.oneLineSerialize(value) - else - value = tostring(value) - end - text = text:gsub('$' .. index, value) - end - end - local fName = nil - local cLine = nil - if debug then - local dInfo = debug.getinfo(3) - fName = dInfo.name - cLine = dInfo.currentline - -- local fsrc = dinfo.short_src - --local fLine = dInfo.linedefined - end - if fName and cLine then - return fName .. '|' .. cLine .. ': ' .. text - elseif cLine then - return cLine .. ': ' .. text - else - return ' ' .. text - end - end - - local function splitText(text) - local tbl = {} - while text:len() > 4000 do - local sub = text:sub(1, 4000) - text = text:sub(4001) - table.insert(tbl, sub) - end - table.insert(tbl, text) - return tbl - end - - --- Creates a new logger. - -- Each logger has it's own tag and log level. - -- @tparam string tag tag which appears at the start of - -- every log line produced by this logger. - -- @tparam[opt] number|string level the log level defines which messages - -- will be logged and which will be omitted. Log level 3 beeing the most verbose - -- and 0 disabling all output. This can also be a string. Allowed strings are: - -- "none" (0), "error" (1), "warning" (2) and "info" (3). - -- @usage myLogger = mist.Logger:new("MyScript") - -- @usage myLogger = mist.Logger:new("MyScript", 2) - -- @usage myLogger = mist.Logger:new("MyScript", "info") - -- @treturn mist.Logger - function mist.Logger:new(tag, level) - local l = {tag = tag} - setmetatable(l, self) - self.__index = self - l:setLevel(level) - return l - end - - --- Sets the level of verbosity for this logger. - -- @tparam[opt] number|string level the log level defines which messages - -- will be logged and which will be omitted. Log level 3 beeing the most verbose - -- and 0 disabling all output. This can also[ be a string. Allowed strings are: - -- "none" (0), "error" (1), "warning" (2) and "info" (3). - -- @usage myLogger:setLevel("info") - -- @usage -- log everything - --myLogger:setLevel(3) - function mist.Logger:setLevel(level) - if not level then - self.level = 2 - else - if type(level) == 'string' then - if level == 'none' or level == 'off' then - self.level = 0 - elseif level == 'error' then - self.level = 1 - elseif level == 'warning' or level == 'warn' then - self.level = 2 - elseif level == 'info' then - self.level = 3 - end - elseif type(level) == 'number' then - self.level = level - else - self.level = 2 - end - end - end - - --- Logs error and shows alert window. - -- This logs an error to the dcs.log and shows a popup window, - -- pausing the simulation. This works always even if logging is - -- disabled by setting a log level of "none" or 0. - -- @tparam string text the text with keywords to substitute. - -- @param ... variables to be used for substitution. - -- @usage myLogger:alert("Shit just hit the fan! WEEEE!!!11") - function mist.Logger:alert(text, ...) - text = formatText(text, unpack(arg)) - if text:len() > 4000 then - local texts = splitText(text) - for i = 1, #texts do - if i == 1 then - env.error(self.tag .. '|' .. texts[i], true) - else - env.error(texts[i]) - end - end - else - env.error(self.tag .. '|' .. text, true) - end - end - - --- Logs a message, disregarding the log level. - -- @tparam string text the text with keywords to substitute. - -- @param ... variables to be used for substitution. - -- @usage myLogger:msg("Always logged!") - function mist.Logger:msg(text, ...) - text = formatText(text, unpack(arg)) - if text:len() > 4000 then - local texts = splitText(text) - for i = 1, #texts do - if i == 1 then - env.info(self.tag .. '|' .. texts[i]) - else - env.info(texts[i]) - end - end - else - env.info(self.tag .. '|' .. text) - end - end - - --- Logs an error. - -- logs a message prefixed with this loggers tag to dcs.log as - -- long as at least the "error" log level (1) is set. - -- @tparam string text the text with keywords to substitute. - -- @param ... variables to be used for substitution. - -- @usage myLogger:error("Just an error!") - -- @usage myLogger:error("Foo is $1 instead of $2", foo, "bar") - function mist.Logger:error(text, ...) - if self.level >= 1 then - text = formatText(text, unpack(arg)) - if text:len() > 4000 then - local texts = splitText(text) - for i = 1, #texts do - if i == 1 then - env.error(self.tag .. '|' .. texts[i]) - else - env.error(texts[i]) - end - end - else - env.error(self.tag .. '|' .. text, mistSettings.errorPopup) - end - end - end - - --- Logs a warning. - -- logs a message prefixed with this loggers tag to dcs.log as - -- long as at least the "warning" log level (2) is set. - -- @tparam string text the text with keywords to substitute. - -- @param ... variables to be used for substitution. - -- @usage myLogger:warn("Mother warned you! Those $1 from the interwebs are $2", {"geeks", 1337}) - function mist.Logger:warn(text, ...) - if self.level >= 2 then - text = formatText(text, unpack(arg)) - if text:len() > 4000 then - local texts = splitText(text) - for i = 1, #texts do - if i == 1 then - env.warning(self.tag .. '|' .. texts[i]) - else - env.warning(texts[i]) - end - end - else - env.warning(self.tag .. '|' .. text, mistSettings.warnPopup) - end - end - end - - --- Logs a info. - -- logs a message prefixed with this loggers tag to dcs.log as - -- long as the highest log level (3) "info" is set. - -- @tparam string text the text with keywords to substitute. - -- @param ... variables to be used for substitution. - -- @see warn - function mist.Logger:info(text, ...) - if self.level >= 3 then - text = formatText(text, unpack(arg)) - if text:len() > 4000 then - local texts = splitText(text) - for i = 1, #texts do - if i == 1 then - env.info(self.tag .. '|' .. texts[i]) - else - env.info(texts[i]) - end - end - else - env.info(self.tag .. '|' .. text, mistSettings.infoPopup) - end - end - end - -end - - --- initialize mist -mist.init() -env.info(('Mist version ' .. mist.majorVersion .. '.' .. mist.minorVersion .. '.' .. mist.build .. ' loaded.')) - --- vim: noet:ts=2:sw=2 diff --git a/resources/plugins/base/plugin.json b/resources/plugins/base/plugin.json deleted file mode 100644 index 3f39e2de5..000000000 --- a/resources/plugins/base/plugin.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "skipUI": true, - "nameInUI": "", - "defaultValue": true, - "specificOptions": [], - "scriptsWorkOrders": [ - { - "file": "mist_4_5_107.lua", - "mnemonic": "mist" - }, - { - "file": "json.lua", - "mnemonic": "json" - }, - { - "file": "dcs_liberation.lua", - "mnemonic": "liberation" - } - ], - "configurationWorkOrders": [] -} \ No newline at end of file diff --git a/resources/plugins/ctld/CTLD.lua b/resources/plugins/ctld/CTLD.lua deleted file mode 100644 index 0e091b4f5..000000000 --- a/resources/plugins/ctld/CTLD.lua +++ /dev/null @@ -1,6427 +0,0 @@ ---[[ - Combat Troop and Logistics Drop - - Allows Huey, Mi-8 and C130 to transport troops internally and Helicopters to transport Logistic / Vehicle units to the field via sling-loads - without requiring external mods. - - Supports all of the original CTTS functionality such as AI auto troop load and unload as well as group spawning and preloading of troops into units. - - Supports deployment of Auto Lasing JTAC to the field - - See https://github.com/ciribob/DCS-CTLD for a user manual and the latest version - - Contributors: - - Steggles - https://github.com/Bob7heBuilder - - mvee - https://github.com/mvee - - jmontleon - https://github.com/jmontleon - - emilianomolina - https://github.com/emilianomolina - - davidp57 - https://github.com/veaf - - - Allow minimum distance from friendly logistics to be set - ]] - -ctld = {} -- DONT REMOVE! - ---- Identifier. All output in DCS.log will start with this. -ctld.Id = "CTLD - " - ---- Version. -ctld.Version = "20211113.01" - --- debug level, specific to this module -ctld.Debug = true --- trace level, specific to this module -ctld.Trace = true - -ctld.alreadyInitialized = false -- if true, ctld.initialize() will not run - --- ************************************************************************ --- ********************* USER CONFIGURATION ****************************** --- ************************************************************************ -ctld.staticBugWorkaround = false -- DCS had a bug where destroying statics would cause a crash. If this happens again, set this to TRUE - -ctld.disableAllSmoke = false -- if true, all smoke is diabled at pickup and drop off zones regardless of settings below. Leave false to respect settings below - -ctld.hoverPickup = true -- if set to false you can load crates with the F10 menu instead of hovering... Only if not using real crates! - -ctld.enableCrates = true -- if false, Helis will not be able to spawn or unpack crates so will be normal CTTS -ctld.slingLoad = false -- if false, crates can be used WITHOUT slingloading, by hovering above the crate, simulating slingloading but not the weight... --- There are some bug with Sling-loading that can cause crashes, if these occur set slingLoad to false --- to use the other method. --- Set staticBugFix to FALSE if use set ctld.slingLoad to TRUE - -ctld.enableSmokeDrop = true -- if false, helis and c-130 will not be able to drop smoke - -ctld.maxExtractDistance = 125 -- max distance from vehicle to troops to allow a group extraction -ctld.maximumDistanceLogistic = 200 -- max distance from vehicle to logistics to allow a loading or spawning operation -ctld.maximumSearchDistance = 4000 -- max distance for troops to search for enemy -ctld.maximumMoveDistance = 2000 -- max distance for troops to move from drop point if no enemy is nearby - -ctld.minimumDeployDistance = 1000 -- minimum distance from a friendly pickup zone where you can deploy a crate - -ctld.numberOfTroops = 10 -- default number of troops to load on a transport heli or C-130 - -- also works as maximum size of group that'll fit into a helicopter unless overridden -ctld.enableFastRopeInsertion = true -- allows you to drop troops by fast rope -ctld.fastRopeMaximumHeight = 18.28 -- in meters which is 60 ft max fast rope (not rappell) safe height - -ctld.vehiclesForTransportRED = { "BRDM-2", "BTR_D" } -- vehicles to load onto Il-76 - Alternatives {"Strela-1 9P31","BMP-1"} -ctld.vehiclesForTransportBLUE = { "M1045 HMMWV TOW", "M1043 HMMWV Armament" } -- vehicles to load onto c130 - Alternatives {"M1128 Stryker MGS","M1097 Avenger"} -ctld.vehiclesWeight = { - ["BRDM-2"] = 7000, - ["BTR_D"] = 8000, - ["M1045 HMMWV TOW"] = 3220, - ["M1043 HMMWV Armament"] = 2500 -} - -ctld.aaLaunchers = 3 -- controls how many launchers to add to the kub/buk when its spawned. -ctld.hawkLaunchers = 8 -- controls how many launchers to add to the hawk when its spawned. - -ctld.spawnRPGWithCoalition = true --spawns a friendly RPG unit with Coalition forces -ctld.spawnStinger = false -- spawns a stinger / igla soldier with a group of 6 or more soldiers! - -ctld.enabledFOBBuilding = true -- if true, you can load a crate INTO a C-130 than when unpacked creates a Forward Operating Base (FOB) which is a new place to spawn (crates) and carry crates from --- In future i'd like it to be a FARP but so far that seems impossible... --- You can also enable troop Pickup at FOBS - -ctld.cratesRequiredForFOB = 3 -- The amount of crates required to build a FOB. Once built, helis can spawn crates at this outpost to be carried and deployed in another area. --- The large crates can only be loaded and dropped by large aircraft, like the C-130 and listed in ctld.vehicleTransportEnabled --- Small FOB crates can be moved by helicopter. The FOB will require ctld.cratesRequiredForFOB larges crates and small crates are 1/3 of a large fob crate --- To build the FOB entirely out of small crates you will need ctld.cratesRequiredForFOB * 3 - -ctld.troopPickupAtFOB = true -- if true, troops can also be picked up at a created FOB - -ctld.buildTimeFOB = 120 --time in seconds for the FOB to be built - -ctld.crateWaitTime = 120 -- time in seconds to wait before you can spawn another crate - -ctld.forceCrateToBeMoved = true -- a crate must be picked up at least once and moved before it can be unpacked. Helps to reduce crate spam - -ctld.radioSound = "beacon.ogg" -- the name of the sound file to use for the FOB radio beacons. If this isnt added to the mission BEACONS WONT WORK! -ctld.radioSoundFC3 = "beaconsilent.ogg" -- name of the second silent radio file, used so FC3 aircraft dont hear ALL the beacon noises... :) - -ctld.deployedBeaconBattery = 30 -- the battery on deployed beacons will last for this number minutes before needing to be re-deployed - -ctld.enabledRadioBeaconDrop = true -- if its set to false then beacons cannot be dropped by units - -ctld.allowRandomAiTeamPickups = false -- Allows the AI to randomize the loading of infantry teams (specified below) at pickup zones - --- Simulated Sling load configuration - -ctld.minimumHoverHeight = 7.5 -- Lowest allowable height for crate hover -ctld.maximumHoverHeight = 12.0 -- Highest allowable height for crate hover -ctld.maxDistanceFromCrate = 5.5 -- Maximum distance from from crate for hover -ctld.hoverTime = 10 -- Time to hold hover above a crate for loading in seconds - --- end of Simulated Sling load configuration - --- AA SYSTEM CONFIG -- --- Sets a limit on the number of active AA systems that can be built for RED. --- A system is counted as Active if its fully functional and has all parts --- If a system is partially destroyed, it no longer counts towards the total --- When this limit is hit, a player will still be able to get crates for an AA system, just unable --- to unpack them - -ctld.AASystemLimitRED = 20 -- Red side limit - -ctld.AASystemLimitBLUE = 20 -- Blue side limit - ---END AA SYSTEM CONFIG -- - --- ***************** JTAC CONFIGURATION ***************** - -ctld.JTAC_LIMIT_RED = 10 -- max number of JTAC Crates for the RED Side -ctld.JTAC_LIMIT_BLUE = 10 -- max number of JTAC Crates for the BLUE Side - -ctld.JTAC_dropEnabled = true -- allow JTAC Crate spawn from F10 menu - -ctld.JTAC_maxDistance = 10000 -- How far a JTAC can "see" in meters (with Line of Sight) - -ctld.JTAC_smokeOn_RED = true -- enables marking of target with smoke for RED forces -ctld.JTAC_smokeOn_BLUE = true -- enables marking of target with smoke for BLUE forces - -ctld.JTAC_smokeColour_RED = 4 -- RED side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4 -ctld.JTAC_smokeColour_BLUE = 1 -- BLUE side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4 - -ctld.JTAC_jtacStatusF10 = true -- enables F10 JTAC Status menu - -ctld.JTAC_location = true -- shows location of target in JTAC message -ctld.location_DMS = false -- shows coordinates as Degrees Minutes Seconds instead of Degrees Decimal minutes - -ctld.JTAC_lock = "all" -- "vehicle" OR "troop" OR "all" forces JTAC to only lock vehicles or troops or all ground units - --- ***************** Pickup, dropoff and waypoint zones ***************** - --- Available colors (anything else like "none" disables smoke): "green", "red", "white", "orange", "blue", "none", - --- Use any of the predefined names or set your own ones - --- You can add number as a third option to limit the number of soldier or vehicle groups that can be loaded from a zone. --- Dropping back a group at a limited zone will add one more to the limit - --- If a zone isn't ACTIVE then you can't pickup from that zone until the zone is activated by ctld.activatePickupZone --- using the Mission editor - --- You can pickup from a SHIP by adding the SHIP UNIT NAME instead of a zone name - --- Side - Controls which side can load/unload troops at the zone - --- Flag Number - Optional last field. If set the current number of groups remaining can be obtained from the flag value - ---pickupZones = { "Zone name or Ship Unit Name", "smoke color", "limit (-1 unlimited)", "ACTIVE (yes/no)", "side (0 = Both sides / 1 = Red / 2 = Blue )", flag number (optional) } -ctld.pickupZones = { - { "pickzone1", "blue", -1, "yes", 0 }, - { "pickzone2", "red", -1, "yes", 0 }, - { "pickzone3", "none", -1, "yes", 0 }, - { "pickzone4", "none", -1, "yes", 0 }, - { "pickzone5", "none", -1, "yes", 0 }, - { "pickzone6", "none", -1, "yes", 0 }, - { "pickzone7", "none", -1, "yes", 0 }, - { "pickzone8", "none", -1, "yes", 0 }, - { "pickzone9", "none", 5, "yes", 1 }, -- limits pickup zone 9 to 5 groups of soldiers or vehicles, only red can pick up - { "pickzone10", "none", 10, "yes", 2 }, -- limits pickup zone 10 to 10 groups of soldiers or vehicles, only blue can pick up - - { "pickzone11", "blue", 20, "no", 2 }, -- limits pickup zone 11 to 20 groups of soldiers or vehicles, only blue can pick up. Zone starts inactive! - { "pickzone12", "red", 20, "no", 1 }, -- limits pickup zone 11 to 20 groups of soldiers or vehicles, only blue can pick up. Zone starts inactive! - { "pickzone13", "none", -1, "yes", 0 }, - { "pickzone14", "none", -1, "yes", 0 }, - { "pickzone15", "none", -1, "yes", 0 }, - { "pickzone16", "none", -1, "yes", 0 }, - { "pickzone17", "none", -1, "yes", 0 }, - { "pickzone18", "none", -1, "yes", 0 }, - { "pickzone19", "none", 5, "yes", 0 }, - { "pickzone20", "none", 10, "yes", 0, 1000 }, -- optional extra flag number to store the current number of groups available in - - { "USA Carrier", "blue", 10, "yes", 0, 1001 }, -- instead of a Zone Name you can also use the UNIT NAME of a ship -} - - --- dropOffZones = {"name","smoke colour",0,side 1 = Red or 2 = Blue or 0 = Both sides} -ctld.dropOffZones = { - { "dropzone1", "green", 2 }, - { "dropzone2", "blue", 2 }, - { "dropzone3", "orange", 2 }, - { "dropzone4", "none", 2 }, - { "dropzone5", "none", 1 }, - { "dropzone6", "none", 1 }, - { "dropzone7", "none", 1 }, - { "dropzone8", "none", 1 }, - { "dropzone9", "none", 1 }, - { "dropzone10", "none", 1 }, -} - - ---wpZones = { "Zone name", "smoke color", "ACTIVE (yes/no)", "side (0 = Both sides / 1 = Red / 2 = Blue )", } -ctld.wpZones = { - { "wpzone1", "green","yes", 2 }, - { "wpzone2", "blue","yes", 2 }, - { "wpzone3", "orange","yes", 2 }, - { "wpzone4", "none","yes", 2 }, - { "wpzone5", "none","yes", 2 }, - { "wpzone6", "none","yes", 1 }, - { "wpzone7", "none","yes", 1 }, - { "wpzone8", "none","yes", 1 }, - { "wpzone9", "none","yes", 1 }, - { "wpzone10", "none","no", 0 }, -- Both sides as its set to 0 -} - - --- ******************** Transports names ********************** - --- Use any of the predefined names or set your own ones -ctld.transportPilotNames = { - "helicargo1", - "helicargo2", - "helicargo3", - "helicargo4", - "helicargo5", - "helicargo6", - "helicargo7", - "helicargo8", - "helicargo9", - "helicargo10", - - "helicargo11", - "helicargo12", - "helicargo13", - "helicargo14", - "helicargo15", - "helicargo16", - "helicargo17", - "helicargo18", - "helicargo19", - "helicargo20", - - "helicargo21", - "helicargo22", - "helicargo23", - "helicargo24", - "helicargo25", - - "MEDEVAC #1", - "MEDEVAC #2", - "MEDEVAC #3", - "MEDEVAC #4", - "MEDEVAC #5", - "MEDEVAC #6", - "MEDEVAC #7", - "MEDEVAC #8", - "MEDEVAC #9", - "MEDEVAC #10", - "MEDEVAC #11", - "MEDEVAC #12", - "MEDEVAC #13", - "MEDEVAC #14", - "MEDEVAC #15", - "MEDEVAC #16", - - "MEDEVAC RED #1", - "MEDEVAC RED #2", - "MEDEVAC RED #3", - "MEDEVAC RED #4", - "MEDEVAC RED #5", - "MEDEVAC RED #6", - "MEDEVAC RED #7", - "MEDEVAC RED #8", - "MEDEVAC RED #9", - "MEDEVAC RED #10", - "MEDEVAC RED #11", - "MEDEVAC RED #12", - "MEDEVAC RED #13", - "MEDEVAC RED #14", - "MEDEVAC RED #15", - "MEDEVAC RED #16", - "MEDEVAC RED #17", - "MEDEVAC RED #18", - "MEDEVAC RED #19", - "MEDEVAC RED #20", - "MEDEVAC RED #21", - - "MEDEVAC BLUE #1", - "MEDEVAC BLUE #2", - "MEDEVAC BLUE #3", - "MEDEVAC BLUE #4", - "MEDEVAC BLUE #5", - "MEDEVAC BLUE #6", - "MEDEVAC BLUE #7", - "MEDEVAC BLUE #8", - "MEDEVAC BLUE #9", - "MEDEVAC BLUE #10", - "MEDEVAC BLUE #11", - "MEDEVAC BLUE #12", - "MEDEVAC BLUE #13", - "MEDEVAC BLUE #14", - "MEDEVAC BLUE #15", - "MEDEVAC BLUE #16", - "MEDEVAC BLUE #17", - "MEDEVAC BLUE #18", - "MEDEVAC BLUE #19", - "MEDEVAC BLUE #20", - "MEDEVAC BLUE #21", - - -- *** AI transports names (different names only to ease identification in mission) *** - - -- Use any of the predefined names or set your own ones - - "transport1", - "transport2", - "transport3", - "transport4", - "transport5", - "transport6", - "transport7", - "transport8", - "transport9", - "transport10", - - "transport11", - "transport12", - "transport13", - "transport14", - "transport15", - "transport16", - "transport17", - "transport18", - "transport19", - "transport20", - - "transport21", - "transport22", - "transport23", - "transport24", - "transport25", -} - --- *************** Optional Extractable GROUPS ***************** - --- Use any of the predefined names or set your own ones - -ctld.extractableGroups = { - "extract1", - "extract2", - "extract3", - "extract4", - "extract5", - "extract6", - "extract7", - "extract8", - "extract9", - "extract10", - - "extract11", - "extract12", - "extract13", - "extract14", - "extract15", - "extract16", - "extract17", - "extract18", - "extract19", - "extract20", - - "extract21", - "extract22", - "extract23", - "extract24", - "extract25", -} - --- ************** Logistics UNITS FOR CRATE SPAWNING ****************** - --- Use any of the predefined names or set your own ones --- When a logistic unit is destroyed, you will no longer be able to spawn crates - -ctld.logisticUnits = { - "logistic1", - "logistic2", - "logistic3", - "logistic4", - "logistic5", - "logistic6", - "logistic7", - "logistic8", - "logistic9", - "logistic10", -} - --- ************** UNITS ABLE TO TRANSPORT VEHICLES ****************** --- Add the model name of the unit that you want to be able to transport and deploy vehicles --- units db has all the names or you can extract a mission.miz file by making it a zip and looking --- in the contained mission file -ctld.vehicleTransportEnabled = { - "76MD", -- the il-76 mod doesnt use a normal - sign so il-76md wont match... !!!! GRR - "Hercules", -} - - --- ************** Maximum Units SETUP for UNITS ****************** - --- Put the name of the Unit you want to limit group sizes too --- i.e --- ["UH-1H"] = 10, --- --- Will limit UH1 to only transport groups with a size 10 or less --- Make sure the unit name is exactly right or it wont work - -ctld.unitLoadLimits = { - - -- Remove the -- below to turn on options - -- ["SA342Mistral"] = 4, - -- ["SA342L"] = 4, - -- ["SA342M"] = 4, - -} - - --- ************** Allowable actions for UNIT TYPES ****************** - --- Put the name of the Unit you want to limit actions for --- NOTE - the unit must've been listed in the transportPilotNames list above --- This can be used in conjunction with the options above for group sizes --- By default you can load both crates and troops unless overriden below --- i.e --- ["UH-1H"] = {crates=true, troops=false}, --- --- Will limit UH1 to only transport CRATES but NOT TROOPS --- --- ["SA342Mistral"] = {crates=fales, troops=true}, --- Will allow Mistral Gazelle to only transport crates, not troops - -ctld.unitActions = { - - -- Remove the -- below to turn on options - -- ["SA342Mistral"] = {crates=true, troops=true}, - -- ["SA342L"] = {crates=false, troops=true}, - -- ["SA342M"] = {crates=false, troops=true}, - -} - --- ************** WEIGHT CALCULATIONS FOR INFANTRY GROUPS ****************** - --- Infantry groups weight is calculated based on the soldiers' roles, and the weight of their kit --- Every soldier weights between 90% and 120% of ctld.SOLDIER_WEIGHT, and they all carry a backpack and their helmet (ctld.KIT_WEIGHT) --- Standard grunts have a rifle and ammo (ctld.RIFLE_WEIGHT) --- AA soldiers have a MANPAD tube (ctld.MANPAD_WEIGHT) --- Anti-tank soldiers have a RPG and a rocket (ctld.RPG_WEIGHT) --- Machine gunners have the squad MG and 200 bullets (ctld.MG_WEIGHT) --- JTAC have the laser sight, radio and binoculars (ctld.JTAC_WEIGHT) --- Mortar servants carry their tube and a few rounds (ctld.MORTAR_WEIGHT) - -ctld.SOLDIER_WEIGHT = 80 -- kg, will be randomized between 90% and 120% -ctld.KIT_WEIGHT = 20 -- kg -ctld.RIFLE_WEIGHT = 5 -- kg -ctld.MANPAD_WEIGHT = 18 -- kg -ctld.RPG_WEIGHT = 7.6 -- kg -ctld.MG_WEIGHT = 10 -- kg -ctld.MORTAR_WEIGHT = 26 -- kg -ctld.JTAC_WEIGHT = 15 -- kg - --- ************** INFANTRY GROUPS FOR PICKUP ****************** --- Unit Types --- inf is normal infantry --- mg is M249 --- at is RPG-16 --- aa is Stinger or Igla --- mortar is a 2B11 mortar unit --- jtac is a JTAC soldier, which will use JTACAutoLase --- You must add a name to the group for it to work --- You can also add an optional coalition side to limit the group to one side --- for the side - 2 is BLUE and 1 is RED -ctld.loadableGroups = { - {name = "Standard Group", inf = 6, mg = 2, at = 2 }, -- will make a loadable group with 6 infantry, 2 MGs and 2 anti-tank for both coalitions - {name = "Anti Air", inf = 2, aa = 3 }, - {name = "Anti Tank", inf = 2, at = 6 }, - {name = "Mortar Squad", mortar = 6 }, - {name = "JTAC Group", inf = 4, jtac = 1 }, -- will make a loadable group with 4 infantry and a JTAC soldier for both coalitions - {name = "Single JTAC", jtac = 1 }, -- will make a loadable group witha single JTAC soldier for both coalitions - -- {name = "Mortar Squad Red", inf = 2, mortar = 5, side =1 }, --would make a group loadable by RED only -} - --- ************** SPAWNABLE CRATES ****************** --- Weights must be unique as we use the weight to change the cargo to the correct unit --- when we unpack --- -ctld.spawnableCrates = { - -- name of the sub menu on F10 for spawning crates - ["Ground Forces"] = { - --crates you can spawn - -- weight in KG - -- Desc is the description on the F10 MENU - -- unit is the model name of the unit to spawn - -- cratesRequired - if set requires that many crates of the same type within 100m of each other in order build the unit - -- side is optional but 2 is BLUE and 1 is RED - -- dont use that option with the HAWK Crates - { weight = 500, desc = "HMMWV - TOW", unit = "M1045 HMMWV TOW", side = 2 }, - { weight = 505, desc = "HMMWV - MG", unit = "M1043 HMMWV Armament", side = 2 }, - - { weight = 510, desc = "BTR-D", unit = "BTR_D", side = 1 }, - { weight = 515, desc = "BRDM-2", unit = "BRDM-2", side = 1 }, - - { weight = 520, desc = "HMMWV - JTAC", unit = "Hummer", side = 2, }, -- used as jtac and unarmed, not on the crate list if JTAC is disabled - { weight = 525, desc = "SKP-11 - JTAC", unit = "SKP-11", side = 1, }, -- used as jtac and unarmed, not on the crate list if JTAC is disabled - - { weight = 100, desc = "2B11 Mortar", unit = "2B11 mortar" }, - - { weight = 250, desc = "SPH 2S19 Msta", unit = "SAU Msta", side = 1, cratesRequired = 3 }, - { weight = 255, desc = "M-109", unit = "M-109", side = 2, cratesRequired = 3 }, - - { weight = 252, desc = "Ural-375 Ammo Truck", unit = "Ural-375", side = 1, cratesRequired = 2 }, - { weight = 253, desc = "M-818 Ammo Truck", unit = "M 818", side = 2, cratesRequired = 2 }, - - { weight = 800, desc = "FOB Crate - Small", unit = "FOB-SMALL" }, -- Builds a FOB! - requires 3 * ctld.cratesRequiredForFOB - }, - ["AA short range"] = { - { weight = 50, desc = "Stinger", unit = "Soldier stinger", side = 2 }, - { weight = 55, desc = "Igla", unit = "SA-18 Igla manpad", side = 1 }, - - { weight = 405, desc = "Strela-1 9P31", unit = "Strela-1 9P31", side = 1, cratesRequired = 3 }, - { weight = 400, desc = "M1097 Avenger", unit = "M1097 Avenger", side = 2, cratesRequired = 3 }, - }, - ["AA mid range"] = { - -- HAWK System - { weight = 540, desc = "HAWK Launcher", unit = "Hawk ln", side = 2}, - { weight = 545, desc = "HAWK Search Radar", unit = "Hawk sr", side = 2 }, - { weight = 546, desc = "HAWK Track Radar", unit = "Hawk tr", side = 2 }, - { weight = 547, desc = "HAWK PCP", unit = "Hawk pcp" , side = 2 }, -- Remove this if on 1.2 - { weight = 548, desc = "HAWK CWAR", unit = "Hawk cwar" , side = 2 }, -- Remove this if on 2.5 - { weight = 549, desc = "HAWK Repair", unit = "HAWK Repair" , side = 2 }, - -- End of HAWK - - -- KUB SYSTEM - { weight = 560, desc = "KUB Launcher", unit = "Kub 2P25 ln", side = 1}, - { weight = 565, desc = "KUB Radar", unit = "Kub 1S91 str", side = 1 }, - { weight = 570, desc = "KUB Repair", unit = "KUB Repair", side = 1}, - -- End of KUB - - -- BUK System - -- { weight = 575, desc = "BUK Launcher", unit = "SA-11 Buk LN 9A310M1"}, - -- { weight = 580, desc = "BUK Search Radar", unit = "SA-11 Buk SR 9S18M1"}, - -- { weight = 585, desc = "BUK CC Radar", unit = "SA-11 Buk CC 9S470M1"}, - -- { weight = 590, desc = "BUK Repair", unit = "BUK Repair"}, - -- END of BUK - }, - ["AA long range"] = { - -- Patriot System - { weight = 555, desc = "Patriot Launcher", unit = "Patriot ln", side = 2 }, - { weight = 556, desc = "Patriot Radar", unit = "Patriot str" , side = 2 }, - { weight = 557, desc = "Patriot ECS", unit = "Patriot ECS", side = 2 }, - -- { weight = 553, desc = "Patriot ICC", unit = "Patriot cp", side = 2 }, - -- { weight = 554, desc = "Patriot EPP", unit = "Patriot EPP", side = 2 }, - { weight = 558, desc = "Patriot AMG (optional)", unit = "Patriot AMG" , side = 2 }, - { weight = 559, desc = "Patriot Repair", unit = "Patriot Repair" , side = 2 }, - -- End of Patriot - - { weight = 595, desc = "Early Warning Radar", unit = "1L13 EWR", side = 1 }, -- cant be used by BLUE coalition - }, -} - ---- 3D model that will be used to represent a loadable crate ; by default, a generator -ctld.spawnableCratesModel_load = { - ["category"] = "Fortifications", - ["shape_name"] = "GeneratorF", - ["type"] = "GeneratorF" -} - ---- 3D model that will be used to represent a slingable crate ; by default, a crate -ctld.spawnableCratesModel_sling = { - ["category"] = "Cargos", - ["shape_name"] = "bw_container_cargo", - ["type"] = "container_cargo" -} - ---[[ Placeholder for different type of cargo containers. Let's say pipes and trunks, fuel for FOB building - ["shape_name"] = "ab-212_cargo", - ["type"] = "uh1h_cargo" --new type for the container previously used - - ["shape_name"] = "ammo_box_cargo", - ["type"] = "ammo_cargo", - - ["shape_name"] = "barrels_cargo", - ["type"] = "barrels_cargo", - - ["shape_name"] = "bw_container_cargo", - ["type"] = "container_cargo", - - ["shape_name"] = "f_bar_cargo", - ["type"] = "f_bar_cargo", - - ["shape_name"] = "fueltank_cargo", - ["type"] = "fueltank_cargo", - - ["shape_name"] = "iso_container_cargo", - ["type"] = "iso_container", - - ["shape_name"] = "iso_container_small_cargo", - ["type"] = "iso_container_small", - - ["shape_name"] = "oiltank_cargo", - ["type"] = "oiltank_cargo", - - ["shape_name"] = "pipes_big_cargo", - ["type"] = "pipes_big_cargo", - - ["shape_name"] = "pipes_small_cargo", - ["type"] = "pipes_small_cargo", - - ["shape_name"] = "tetrapod_cargo", - ["type"] = "tetrapod_cargo", - - ["shape_name"] = "trunks_long_cargo", - ["type"] = "trunks_long_cargo", - - ["shape_name"] = "trunks_small_cargo", - ["type"] = "trunks_small_cargo", -]]-- - --- if the unit is on this list, it will be made into a JTAC when deployed -ctld.jtacUnitTypes = { - "SKP", "Hummer" -- there are some wierd encoding issues so if you write SKP-11 it wont match as the - sign is encoded differently... -} - - --- *************************************************************** --- **************** Mission Editor Functions ********************* --- *************************************************************** - - ------------------------------------------------------------------ --- Spawn group at a trigger and set them as extractable. Usage: --- ctld.spawnGroupAtTrigger("groupside", number, "triggerName", radius) --- Variables: --- "groupSide" = "red" for Russia "blue" for USA --- _number = number of groups to spawn OR Group description --- "triggerName" = trigger name in mission editor between commas --- _searchRadius = random distance for units to move from spawn zone (0 will leave troops at the spawn position - no search for enemy) --- --- Example: ctld.spawnGroupAtTrigger("red", 2, "spawn1", 1000) --- --- This example will spawn 2 groups of russians at the specified point --- and they will search for enemy or move randomly withing 1000m --- OR --- --- ctld.spawnGroupAtTrigger("blue", {mg=1,at=2,aa=3,inf=4,mortar=5},"spawn2", 2000) --- Spawns 1 machine gun, 2 anti tank, 3 anti air, 4 standard soldiers and 5 mortars --- -function ctld.spawnGroupAtTrigger(_groupSide, _number, _triggerName, _searchRadius) - local _spawnTrigger = trigger.misc.getZone(_triggerName) -- trigger to use as reference position - - if _spawnTrigger == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find trigger called " .. _triggerName, 10) - return - end - - local _country - if _groupSide == "red" then - _groupSide = 1 - _country = 0 - else - _groupSide = 2 - _country = 2 - end - - if _searchRadius < 0 then - _searchRadius = 0 - end - - local _pos2 = { x = _spawnTrigger.point.x, y = _spawnTrigger.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - local _groupDetails = ctld.generateTroopTypes(_groupSide, _number, _country) - - local _droppedTroops = ctld.spawnDroppedGroup(_pos3, _groupDetails, false, _searchRadius); - - if _groupSide == 1 then - table.insert(ctld.droppedTroopsRED, _droppedTroops:getName()) - else - table.insert(ctld.droppedTroopsBLUE, _droppedTroops:getName()) - end -end - - ------------------------------------------------------------------ --- Spawn group at a Vec3 Point and set them as extractable. Usage: --- ctld.spawnGroupAtPoint("groupside", number,Vec3 Point, radius) --- Variables: --- "groupSide" = "red" for Russia "blue" for USA --- _number = number of groups to spawn OR Group Description --- Vec3 Point = A vec3 point like {x=1,y=2,z=3}. Can be obtained from a unit like so: Unit.getName("Unit1"):getPoint() --- _searchRadius = random distance for units to move from spawn zone (0 will leave troops at the spawn position - no search for enemy) --- --- Example: ctld.spawnGroupAtPoint("red", 2, {x=1,y=2,z=3}, 1000) --- --- This example will spawn 2 groups of russians at the specified point --- and they will search for enemy or move randomly withing 1000m --- OR --- --- ctld.spawnGroupAtPoint("blue", {mg=1,at=2,aa=3,inf=4,mortar=5}, {x=1,y=2,z=3}, 2000) --- Spawns 1 machine gun, 2 anti tank, 3 anti air, 4 standard soldiers and 5 mortars -function ctld.spawnGroupAtPoint(_groupSide, _number, _point, _searchRadius) - - local _country - if _groupSide == "red" then - _groupSide = 1 - _country = 0 - else - _groupSide = 2 - _country = 2 - end - - if _searchRadius < 0 then - _searchRadius = 0 - end - - local _groupDetails = ctld.generateTroopTypes(_groupSide, _number, _country) - - local _droppedTroops = ctld.spawnDroppedGroup(_point, _groupDetails, false, _searchRadius); - - if _groupSide == 1 then - table.insert(ctld.droppedTroopsRED, _droppedTroops:getName()) - else - table.insert(ctld.droppedTroopsBLUE, _droppedTroops:getName()) - end -end - - --- Preloads a transport with troops or vehicles --- replaces any troops currently on board -function ctld.preLoadTransport(_unitName, _number, _troops) - - local _unit = ctld.getTransportUnit(_unitName) - - if _unit ~= nil then - - -- will replace any units currently on board - -- if not ctld.troopsOnboard(_unit,_troops) then - ctld.loadTroops(_unit, _troops, _number) - -- end - end -end - - --- Continuously counts the number of crates in a zone and sets the value of the passed in flag --- to the count amount --- This means you can trigger actions based on the count and also trigger messages before the count is reached --- Just pass in the zone name and flag number like so as a single (NOT Continuous) Trigger --- This will now work for Mission Editor and Spawned Crates --- e.g. ctld.cratesInZone("DropZone1", 5) -function ctld.cratesInZone(_zone, _flagNumber) - local _triggerZone = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _zonePos = mist.utils.zoneToVec3(_zone) - - --ignore side, if crate has been used its discounted from the count - local _crateTables = { ctld.spawnedCratesRED, ctld.spawnedCratesBLUE, ctld.missionEditorCargoCrates } - - local _crateCount = 0 - - for _, _crates in pairs(_crateTables) do - - for _crateName, _dontUse in pairs(_crates) do - - --get crate - local _crate = ctld.getCrateObject(_crateName) - - --in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude - if _crate ~= nil and _crate:getLife() > 0 - and (ctld.inAir(_crate) == false) then - - local _dist = ctld.getDistance(_crate:getPoint(), _zonePos) - - if _dist <= _triggerZone.radius then - _crateCount = _crateCount + 1 - end - end - end - end - - --set flag stuff - trigger.action.setUserFlag(_flagNumber, _crateCount) - - -- env.info("FLAG ".._flagNumber.." crates ".._crateCount) - - --retrigger in 5 seconds - timer.scheduleFunction(function(_args) - - ctld.cratesInZone(_args[1], _args[2]) - end, { _zone, _flagNumber }, timer.getTime() + 5) -end - --- Creates an extraction zone --- any Soldiers (not vehicles) dropped at this zone by a helicopter will disappear --- and be added to a running total of soldiers for a set flag number --- The idea is you can then drop say 20 troops in a zone and trigger an action using the mission editor triggers --- and the flag value --- --- The ctld.createExtractZone function needs to be called once in a trigger action do script. --- if you dont want smoke, pass -1 to the function. ---Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4, NO SMOKE = -1 --- --- e.g. ctld.createExtractZone("extractzone1", 2, -1) will create an extraction zone at trigger zone "extractzone1", store the number of troops dropped at --- the zone in flag 2 and not have smoke --- --- --- -function ctld.createExtractZone(_zone, _flagNumber, _smoke) - local _triggerZone = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _pos2 = { x = _triggerZone.point.x, y = _triggerZone.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - trigger.action.setUserFlag(_flagNumber, 0) --start at 0 - - local _details = { point = _pos3, name = _zone, smoke = _smoke, flag = _flagNumber, radius = _triggerZone.radius} - - ctld.extractZones[_zone.."-".._flagNumber] = _details - - if _smoke ~= nil and _smoke > -1 then - - local _smokeFunction - - _smokeFunction = function(_args) - - local _extractDetails = ctld.extractZones[_zone.."-".._flagNumber] - -- check zone is still active - if _extractDetails == nil then - -- stop refreshing smoke, zone is done - return - end - - - trigger.action.smoke(_args.point, _args.smoke) - --refresh in 5 minutes - timer.scheduleFunction(_smokeFunction, _args, timer.getTime() + 300) - end - - --run local function - _smokeFunction(_details) - end -end - - --- Removes an extraction zone --- --- The smoke will take up to 5 minutes to disappear depending on the last time the smoke was activated --- --- The ctld.removeExtractZone function needs to be called once in a trigger action do script. --- --- e.g. ctld.removeExtractZone("extractzone1", 2) will remove an extraction zone at trigger zone "extractzone1" --- that was setup with flag 2 --- --- --- -function ctld.removeExtractZone(_zone,_flagNumber) - - local _extractDetails = ctld.extractZones[_zone.."-".._flagNumber] - - if _extractDetails ~= nil then - --remove zone - ctld.extractZones[_zone.."-".._flagNumber] = nil - - end -end - --- CONTINUOUS TRIGGER FUNCTION --- This function will count the current number of extractable RED and BLUE --- GROUPS in a zone and store the values in two flags --- A group is only counted as being in a zone when the leader of that group --- is in the zone --- Use: ctld.countDroppedGroupsInZone("Zone Name", flagBlue, flagRed) -function ctld.countDroppedGroupsInZone(_zone, _blueFlag, _redFlag) - - local _triggerZone = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _zonePos = mist.utils.zoneToVec3(_zone) - - local _redCount = 0; - local _blueCount = 0; - - local _allGroups = {ctld.droppedTroopsRED,ctld.droppedTroopsBLUE,ctld.droppedVehiclesRED,ctld.droppedVehiclesBLUE} - for _, _extractGroups in pairs(_allGroups) do - for _,_groupName in pairs(_extractGroups) do - local _groupUnits = ctld.getGroup(_groupName) - - if #_groupUnits > 0 then - local _zonePos = mist.utils.zoneToVec3(_zone) - local _dist = ctld.getDistance(_groupUnits[1]:getPoint(), _zonePos) - - if _dist <= _triggerZone.radius then - - if (_groupUnits[1]:getCoalition() == 1) then - _redCount = _redCount + 1; - else - _blueCount = _blueCount + 1; - end - end - end - end - end - --set flag stuff - trigger.action.setUserFlag(_blueFlag, _blueCount) - trigger.action.setUserFlag(_redFlag, _redCount) - - -- env.info("Groups in zone ".._blueCount.." ".._redCount) - -end - --- CONTINUOUS TRIGGER FUNCTION --- This function will count the current number of extractable RED and BLUE --- UNITS in a zone and store the values in two flags - --- Use: ctld.countDroppedUnitsInZone("Zone Name", flagBlue, flagRed) -function ctld.countDroppedUnitsInZone(_zone, _blueFlag, _redFlag) - - local _triggerZone = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _zonePos = mist.utils.zoneToVec3(_zone) - - local _redCount = 0; - local _blueCount = 0; - - local _allGroups = {ctld.droppedTroopsRED,ctld.droppedTroopsBLUE,ctld.droppedVehiclesRED,ctld.droppedVehiclesBLUE} - - for _, _extractGroups in pairs(_allGroups) do - for _,_groupName in pairs(_extractGroups) do - local _groupUnits = ctld.getGroup(_groupName) - - if #_groupUnits > 0 then - - local _zonePos = mist.utils.zoneToVec3(_zone) - for _,_unit in pairs(_groupUnits) do - local _dist = ctld.getDistance(_unit:getPoint(), _zonePos) - - if _dist <= _triggerZone.radius then - - if (_unit:getCoalition() == 1) then - _redCount = _redCount + 1; - else - _blueCount = _blueCount + 1; - end - end - end - end - end - end - - - --set flag stuff - trigger.action.setUserFlag(_blueFlag, _blueCount) - trigger.action.setUserFlag(_redFlag, _redCount) - - -- env.info("Units in zone ".._blueCount.." ".._redCount) -end - - --- Creates a radio beacon on a random UHF - VHF and HF/FM frequency for homing --- This WILL NOT WORK if you dont add beacon.ogg and beaconsilent.ogg to the mission!!! --- e.g. ctld.createRadioBeaconAtZone("beaconZone","red", 1440,"Waypoint 1") will create a beacon at trigger zone "beaconZone" for the Red side --- that will last 1440 minutes (24 hours ) and named "Waypoint 1" in the list of radio beacons --- --- e.g. ctld.createRadioBeaconAtZone("beaconZoneBlue","blue", 20) will create a beacon at trigger zone "beaconZoneBlue" for the Blue side --- that will last 20 minutes -function ctld.createRadioBeaconAtZone(_zone, _coalition, _batteryLife, _name) - local _triggerZone = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _zonePos = mist.utils.zoneToVec3(_zone) - - ctld.beaconCount = ctld.beaconCount + 1 - - if _name == nil or _name == "" then - _name = "Beacon #" .. ctld.beaconCount - end - - if _coalition == "red" then - ctld.createRadioBeacon(_zonePos, 1, 0, _name, _batteryLife) --1440 - else - ctld.createRadioBeacon(_zonePos, 2, 2, _name, _batteryLife) --1440 - end -end - - --- Activates a pickup zone --- Activates a pickup zone when called from a trigger --- EG: ctld.activatePickupZone("pickzone3") --- This is enable pickzone3 to be used as a pickup zone for the team set -function ctld.activatePickupZone(_zoneName) - ctld.logDebug(string.format("ctld.activatePickupZone(_zoneName=%s)", ctld.p(_zoneName))) - - local _triggerZone = trigger.misc.getZone(_zoneName) -- trigger to use as reference position - - if _triggerZone == nil then - local _ship = ctld.getTransportUnit(_triggerZone) - - if _ship then - local _point = _ship:getPoint() - _triggerZone = {} - _triggerZone.point = _point - end - - end - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone or ship called " .. _zoneName, 10) - end - - for _, _zoneDetails in pairs(ctld.pickupZones) do - - if _zoneName == _zoneDetails[1] then - - --smoke could get messy if designer keeps calling this on an active zone, check its not active first - if _zoneDetails[4] == 1 then - -- they might have a continuous trigger so i've hidden the warning - --trigger.action.outText("CTLD.lua ERROR: Pickup Zone already active: " .. _zoneName, 10) - return - end - - _zoneDetails[4] = 1 --activate zone - - if ctld.disableAllSmoke == true then --smoke disabled - return - end - - if _zoneDetails[2] >= 0 then - - -- Trigger smoke marker - -- This will cause an overlapping smoke marker on next refreshsmoke call - -- but will only happen once - local _pos2 = { x = _triggerZone.point.x, y = _triggerZone.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - trigger.action.smoke(_pos3, _zoneDetails[2]) - end - end - end -end - - --- Deactivates a pickup zone --- Deactivates a pickup zone when called from a trigger --- EG: ctld.deactivatePickupZone("pickzone3") --- This is disables pickzone3 and can no longer be used to as a pickup zone --- These functions can be called by triggers, like if a set of buildings is used, you can trigger the zone to be 'not operational' --- once they are destroyed -function ctld.deactivatePickupZone(_zoneName) - - local _triggerZone = trigger.misc.getZone(_zoneName) -- trigger to use as reference position - - if _triggerZone == nil then - local _ship = ctld.getTransportUnit(_triggerZone) - - if _ship then - local _point = _ship:getPoint() - _triggerZone = {} - _triggerZone.point = _point - end - - end - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zoneName, 10) - return - end - - for _, _zoneDetails in pairs(ctld.pickupZones) do - - if _zoneName == _zoneDetails[1] then - - -- i'd just ignore it if its already been deactivated - -- if _zoneDetails[4] == 0 then --this really needed?? - -- trigger.action.outText("CTLD.lua ERROR: Pickup Zone already deactiveated: " .. _zoneName, 10) - -- return - -- end - - _zoneDetails[4] = 0 --deactivate zone - end - end -end - --- Change the remaining groups currently available for pickup at a zone --- e.g. ctld.changeRemainingGroupsForPickupZone("pickup1", 5) -- adds 5 groups --- ctld.changeRemainingGroupsForPickupZone("pickup1", -3) -- remove 3 groups -function ctld.changeRemainingGroupsForPickupZone(_zoneName, _amount) - local _triggerZone = trigger.misc.getZone(_zoneName) -- trigger to use as reference position - - if _triggerZone == nil then - local _ship = ctld.getTransportUnit(_triggerZone) - - if _ship then - local _point = _ship:getPoint() - _triggerZone = {} - _triggerZone.point = _point - end - - end - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ctld.changeRemainingGroupsForPickupZone ERROR: Cant find zone called " .. _zoneName, 10) - return - end - - for _, _zoneDetails in pairs(ctld.pickupZones) do - - if _zoneName == _zoneDetails[1] then - ctld.updateZoneCounter(_zoneName, _amount) - end - end - - -end - --- Activates a Waypoint zone --- Activates a Waypoint zone when called from a trigger --- EG: ctld.activateWaypointZone("pickzone3") --- This means that troops dropped within the radius of the zone will head to the center --- of the zone instead of searching for troops -function ctld.activateWaypointZone(_zoneName) - local _triggerZone = trigger.misc.getZone(_zoneName) -- trigger to use as reference position - - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zoneName, 10) - - return - end - - for _, _zoneDetails in pairs(ctld.wpZones) do - - if _zoneName == _zoneDetails[1] then - - --smoke could get messy if designer keeps calling this on an active zone, check its not active first - if _zoneDetails[3] == 1 then - -- they might have a continuous trigger so i've hidden the warning - --trigger.action.outText("CTLD.lua ERROR: Pickup Zone already active: " .. _zoneName, 10) - return - end - - _zoneDetails[3] = 1 --activate zone - - if ctld.disableAllSmoke == true then --smoke disabled - return - end - - if _zoneDetails[2] >= 0 then - - -- Trigger smoke marker - -- This will cause an overlapping smoke marker on next refreshsmoke call - -- but will only happen once - local _pos2 = { x = _triggerZone.point.x, y = _triggerZone.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - trigger.action.smoke(_pos3, _zoneDetails[2]) - end - end - end -end - - --- Deactivates a Waypoint zone --- Deactivates a Waypoint zone when called from a trigger --- EG: ctld.deactivateWaypointZone("wpzone3") --- This disables wpzone3 so that troops dropped in this zone will search for troops as normal --- These functions can be called by triggers -function ctld.deactivateWaypointZone(_zoneName) - - local _triggerZone = trigger.misc.getZone(_zoneName) - - if _triggerZone == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zoneName, 10) - return - end - - for _, _zoneDetails in pairs(ctld.pickupZones) do - - if _zoneName == _zoneDetails[1] then - - _zoneDetails[3] = 0 --deactivate zone - end - end -end - --- Continuous Trigger Function --- Causes an AI unit with the specified name to unload troops / vehicles when --- an enemy is detected within a specified distance --- The enemy must have Line or Sight to the unit to be detected -function ctld.unloadInProximityToEnemy(_unitName,_distance) - - local _unit = ctld.getTransportUnit(_unitName) - - if _unit ~= nil and _unit:getPlayerName() == nil then - - -- no player name means AI! - -- the findNearest visible enemy you'd want to modify as it'll find enemies quite far away - -- limited by ctld.JTAC_maxDistance - local _nearestEnemy = ctld.findNearestVisibleEnemy(_unit,"all",_distance) - - if _nearestEnemy ~= nil then - - if ctld.troopsOnboard(_unit, true) then - ctld.deployTroops(_unit, true) - return true - end - - if ctld.unitCanCarryVehicles(_unit) and ctld.troopsOnboard(_unit, false) then - ctld.deployTroops(_unit, false) - return true - end - end - end - - return false - -end - - - --- Unit will unload any units onboard if the unit is on the ground --- when this function is called -function ctld.unloadTransport(_unitName) - - local _unit = ctld.getTransportUnit(_unitName) - - if _unit ~= nil then - - if ctld.troopsOnboard(_unit, true) then - ctld.unloadTroops({_unitName,true}) - end - - if ctld.unitCanCarryVehicles(_unit) and ctld.troopsOnboard(_unit, false) then - ctld.unloadTroops({_unitName,false}) - end - end - -end - --- Loads Troops and Vehicles from a zone or picks up nearby troops or vehicles -function ctld.loadTransport(_unitName) - - local _unit = ctld.getTransportUnit(_unitName) - - if _unit ~= nil then - - ctld.loadTroopsFromZone({ _unitName, true,"",true }) - - if ctld.unitCanCarryVehicles(_unit) then - ctld.loadTroopsFromZone({ _unitName, false,"",true }) - end - - end - -end - --- adds a callback that will be called for many actions ingame -function ctld.addCallback(_callback) - - table.insert(ctld.callbacks,_callback) - -end - --- Spawns a sling loadable crate at a Trigger Zone --- --- Weights can be found in the ctld.spawnableCrates list --- e.g. ctld.spawnCrateAtZone("red", 500,"triggerzone1") -- spawn a humvee at triggerzone 1 for red side --- e.g. ctld.spawnCrateAtZone("blue", 505,"triggerzone1") -- spawn a tow humvee at triggerzone1 for blue side --- -function ctld.spawnCrateAtZone(_side, _weight,_zone) - local _spawnTrigger = trigger.misc.getZone(_zone) -- trigger to use as reference position - - if _spawnTrigger == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find zone called " .. _zone, 10) - return - end - - local _crateType = ctld.crateLookupTable[tostring(_weight)] - - if _crateType == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find crate with weight " .. _weight, 10) - return - end - - local _country - if _side == "red" then - _side = 1 - _country = 0 - else - _side = 2 - _country = 2 - end - - local _pos2 = { x = _spawnTrigger.point.x, y = _spawnTrigger.point.z } - local _alt = land.getHeight(_pos2) - local _point = { x = _pos2.x, y = _alt, z = _pos2.y } - - local _unitId = ctld.getNextUnitId() - - local _name = string.format("%s #%i", _crateType.desc, _unitId) - - local _spawnedCrate = ctld.spawnCrateStatic(_country, _unitId, _point, _name, _crateType.weight,_side) - -end - --- Spawns a sling loadable crate at a Point --- --- Weights can be found in the ctld.spawnableCrates list --- Points can be made by hand or obtained from a Unit position by Unit.getByName("PilotName"):getPoint() --- e.g. ctld.spawnCrateAtZone("red", 500,{x=1,y=2,z=3}) -- spawn a humvee at triggerzone 1 for red side at a specified point --- e.g. ctld.spawnCrateAtZone("blue", 505,{x=1,y=2,z=3}) -- spawn a tow humvee at triggerzone1 for blue side at a specified point --- --- -function ctld.spawnCrateAtPoint(_side, _weight,_point) - - - local _crateType = ctld.crateLookupTable[tostring(_weight)] - - if _crateType == nil then - trigger.action.outText("CTLD.lua ERROR: Cant find crate with weight " .. _weight, 10) - return - end - - local _country - if _side == "red" then - _side = 1 - _country = 0 - else - _side = 2 - _country = 2 - end - - local _unitId = ctld.getNextUnitId() - - local _name = string.format("%s #%i", _crateType.desc, _unitId) - - local _spawnedCrate = ctld.spawnCrateStatic(_country, _unitId, _point, _name, _crateType.weight,_side) - -end - --- *************************************************************** --- **************** BE CAREFUL BELOW HERE ************************ --- *************************************************************** - ---- Tells CTLD What multipart AA Systems there are and what parts they need --- A New system added here also needs the launcher added -ctld.AASystemTemplate = { - - { - name = "HAWK AA System", - count = 4, - parts = { - {name = "Hawk ln", desc = "HAWK Launcher", launcher = true}, - {name = "Hawk tr", desc = "HAWK Track Radar"}, - {name = "Hawk sr", desc = "HAWK Search Radar"}, - {name = "Hawk pcp", desc = "HAWK PCP"}, - {name = "Hawk cwar", desc = "HAWK CWAR"}, - }, - repair = "HAWK Repair", - }, - { - name = "Patriot AA System", - count = 4, - parts = { - {name = "Patriot ln", desc = "Patriot Launcher", launcher = true}, - {name = "Patriot ECS", desc = "Patriot Control Unit"}, - {name = "Patriot str", desc = "Patriot Search and Track Radar"}, - }, - repair = "Patriot Repair", - }, - { - name = "BUK AA System", - count = 3, - parts = { - {name = "SA-11 Buk LN 9A310M1", desc = "BUK Launcher" , launcher = true}, - {name = "SA-11 Buk CC 9S470M1", desc = "BUK CC Radar"}, - {name = "SA-11 Buk SR 9S18M1", desc = "BUK Search Radar"}, - }, - repair = "BUK Repair", - }, - { - name = "KUB AA System", - count = 2, - parts = { - {name = "Kub 2P25 ln", desc = "KUB Launcher", launcher = true}, - {name = "Kub 1S91 str", desc = "KUB Radar"}, - }, - repair = "KUB Repair", - }, -} - - -ctld.crateWait = {} -ctld.crateMove = {} - ----------------- INTERNAL FUNCTIONS ---------------- ---- ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Utility methods -------------------------------------------------------------------------------------------------------------------------------------------------------------- - ---- print an object for a debugging log -function ctld.p(o, level) - local MAX_LEVEL = 20 - if level == nil then level = 0 end - if level > MAX_LEVEL then - ctld.logError("max depth reached in ctld.p : "..tostring(MAX_LEVEL)) - return "" - end - local text = "" - if (type(o) == "table") then - text = "\n" - for key,value in pairs(o) do - for i=0, level do - text = text .. " " - end - text = text .. ".".. key.."="..ctld.p(value, level+1) .. "\n" - end - elseif (type(o) == "function") then - text = "[function]" - elseif (type(o) == "boolean") then - if o == true then - text = "[true]" - else - text = "[false]" - end - else - if o == nil then - text = "[nil]" - else - text = tostring(o) - end - end - return text -end - -function ctld.logError(message) - env.info(" E - " .. ctld.Id .. message) -end - -function ctld.logInfo(message) - env.info(" I - " .. ctld.Id .. message) -end - -function ctld.logDebug(message) - if message and ctld.Debug then - env.info(" D - " .. ctld.Id .. message) - end -end - -function ctld.logTrace(message) - if message and ctld.Trace then - env.info(" T - " .. ctld.Id .. message) - end -end - -ctld.nextUnitId = 1; -ctld.getNextUnitId = function() - ctld.nextUnitId = ctld.nextUnitId + 1 - - return ctld.nextUnitId -end - -ctld.nextGroupId = 1; - -ctld.getNextGroupId = function() - ctld.nextGroupId = ctld.nextGroupId + 1 - - return ctld.nextGroupId -end - -function ctld.getTransportUnit(_unitName) - - if _unitName == nil then - return nil - end - - local _heli = Unit.getByName(_unitName) - - if _heli ~= nil and _heli:isActive() and _heli:getLife() > 0 then - - return _heli - end - - return nil -end - -function ctld.spawnCrateStatic(_country, _unitId, _point, _name, _weight,_side) - - local _crate - local _spawnedCrate - - if ctld.staticBugWorkaround and ctld.slingLoad == false then - local _groupId = ctld.getNextGroupId() - local _groupName = "Crate Group #".._groupId - - local _group = { - ["visible"] = false, - -- ["groupId"] = _groupId, - ["hidden"] = false, - ["units"] = {}, - -- ["y"] = _positions[1].z, - -- ["x"] = _positions[1].x, - ["name"] = _groupName, - ["task"] = {}, - } - - _group.units[1] = ctld.createUnit(_point.x , _point.z , 0, {type="UAZ-469",name=_name,unitId=_unitId}) - - --switch to MIST - _group.category = Group.Category.GROUND; - _group.country = _country; - - local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) - - -- Turn off AI - trigger.action.setGroupAIOff(_spawnedGroup) - - _spawnedCrate = Unit.getByName(_name) - else - - if ctld.slingLoad then - _crate = mist.utils.deepCopy(ctld.spawnableCratesModel_sling) - _crate["canCargo"] = true - else - _crate = mist.utils.deepCopy(ctld.spawnableCratesModel_load) - _crate["canCargo"] = false - end - - _crate["y"] = _point.z - _crate["x"] = _point.x - _crate["mass"] = _weight - _crate["name"] = _name - _crate["heading"] = 0 - _crate["country"] = _country - - ctld.logTrace(string.format("_crate=%s", ctld.p(_crate))) - mist.dynAddStatic(_crate) - - _spawnedCrate = StaticObject.getByName(_crate["name"]) - end - - - local _crateType = ctld.crateLookupTable[tostring(_weight)] - - if _side == 1 then - ctld.spawnedCratesRED[_name] =_crateType - else - ctld.spawnedCratesBLUE[_name] = _crateType - end - - return _spawnedCrate -end - -function ctld.spawnFOBCrateStatic(_country, _unitId, _point, _name) - - local _crate = { - ["category"] = "Fortifications", - ["shape_name"] = "konteiner_red1", - ["type"] = "Container red 1", - -- ["unitId"] = _unitId, - ["y"] = _point.z, - ["x"] = _point.x, - ["name"] = _name, - ["canCargo"] = false, - ["heading"] = 0, - } - - _crate["country"] = _country - - mist.dynAddStatic(_crate) - - local _spawnedCrate = StaticObject.getByName(_crate["name"]) - --local _spawnedCrate = coalition.addStaticObject(_country, _crate) - - return _spawnedCrate -end - - -function ctld.spawnFOB(_country, _unitId, _point, _name) - - local _crate = { - ["category"] = "Fortifications", - ["type"] = "outpost", - -- ["unitId"] = _unitId, - ["y"] = _point.z, - ["x"] = _point.x, - ["name"] = _name, - ["canCargo"] = false, - ["heading"] = 0, - } - - _crate["country"] = _country - mist.dynAddStatic(_crate) - local _spawnedCrate = StaticObject.getByName(_crate["name"]) - --local _spawnedCrate = coalition.addStaticObject(_country, _crate) - - local _id = ctld.getNextUnitId() - local _tower = { - ["type"] = "house2arm", - -- ["unitId"] = _id, - ["rate"] = 100, - ["y"] = _point.z + -36.57142857, - ["x"] = _point.x + 14.85714286, - ["name"] = "FOB Watchtower #" .. _id, - ["category"] = "Fortifications", - ["canCargo"] = false, - ["heading"] = 0, - } - --coalition.addStaticObject(_country, _tower) - _tower["country"] = _country - - mist.dynAddStatic(_tower) - - return _spawnedCrate -end - - -function ctld.spawnCrate(_arguments) - - local _status, _err = pcall(function(_args) - - -- use the cargo weight to guess the type of unit as no way to add description :( - - local _crateType = ctld.crateLookupTable[tostring(_args[2])] - local _heli = ctld.getTransportUnit(_args[1]) - - if _crateType ~= nil and _heli ~= nil and ctld.inAir(_heli) == false then - - if ctld.inLogisticsZone(_heli) == false then - - ctld.displayMessageToGroup(_heli, "You are not close enough to friendly logistics to get a crate!", 10) - - return - end - - if ctld.isJTACUnitType(_crateType.unit) then - - local _limitHit = false - - if _heli:getCoalition() == 1 then - - if ctld.JTAC_LIMIT_RED == 0 then - _limitHit = true - else - ctld.JTAC_LIMIT_RED = ctld.JTAC_LIMIT_RED - 1 - end - else - if ctld.JTAC_LIMIT_BLUE == 0 then - _limitHit = true - else - ctld.JTAC_LIMIT_BLUE = ctld.JTAC_LIMIT_BLUE - 1 - end - end - - if _limitHit then - ctld.displayMessageToGroup(_heli, "No more JTAC Crates Left!", 10) - return - end - end - - local _position = _heli:getPosition() - - -- check crate spam - if _heli:getPlayerName() ~= nil and ctld.crateWait[_heli:getPlayerName()] and ctld.crateWait[_heli:getPlayerName()] > timer.getTime() then - - ctld.displayMessageToGroup(_heli,"Sorry you must wait "..(ctld.crateWait[_heli:getPlayerName()] - timer.getTime()).. " seconds before you can get another crate", 20) - return - end - - if _heli:getPlayerName() ~= nil then - ctld.crateWait[_heli:getPlayerName()] = timer.getTime() + ctld.crateWaitTime - end - -- trigger.action.outText("Spawn Crate".._args[1].." ".._args[2],10) - - local _heli = ctld.getTransportUnit(_args[1]) - - local _point = ctld.getPointAt12Oclock(_heli, 30) - - local _unitId = ctld.getNextUnitId() - - local _side = _heli:getCoalition() - - local _name = string.format("%s #%i", _crateType.desc, _unitId) - - local _spawnedCrate = ctld.spawnCrateStatic(_heli:getCountry(), _unitId, _point, _name, _crateType.weight,_side) - - -- add to move table - ctld.crateMove[_name] = _name - - ctld.displayMessageToGroup(_heli, string.format("A %s crate weighing %s kg has been brought out and is at your 12 o'clock ", _crateType.desc, _crateType.weight), 20) - - else - env.info("Couldn't find crate item to spawn") - end - end, _arguments) - - if (not _status) then - env.error(string.format("CTLD ERROR: %s", _err)) - end -end - -function ctld.getPointAt12Oclock(_unit, _offset) - - local _position = _unit:getPosition() - local _angle = math.atan2(_position.x.z, _position.x.x) - local _xOffset = math.cos(_angle) * _offset - local _yOffset = math.sin(_angle) * _offset - - local _point = _unit:getPoint() - return { x = _point.x + _xOffset, z = _point.z + _yOffset, y = _point.y } -end - -function ctld.troopsOnboard(_heli, _troops) - - if ctld.inTransitTroops[_heli:getName()] ~= nil then - - local _onboard = ctld.inTransitTroops[_heli:getName()] - - if _troops then - - if _onboard.troops ~= nil and _onboard.troops.units ~= nil and #_onboard.troops.units > 0 then - return true - else - return false - end - else - - if _onboard.vehicles ~= nil and _onboard.vehicles.units ~= nil and #_onboard.vehicles.units > 0 then - return true - else - return false - end - end - - else - return false - end -end - --- if its dropped by AI then there is no player name so return the type of unit -function ctld.getPlayerNameOrType(_heli) - - if _heli:getPlayerName() == nil then - - return _heli:getTypeName() - else - return _heli:getPlayerName() - end -end - -function ctld.inExtractZone(_heli) - - local _heliPoint = _heli:getPoint() - - for _, _zoneDetails in pairs(ctld.extractZones) do - - --get distance to center - local _dist = ctld.getDistance(_heliPoint, _zoneDetails.point) - - if _dist <= _zoneDetails.radius then - return _zoneDetails - end - end - - return false -end - --- safe to fast rope if speed is less than 0.5 Meters per second -function ctld.safeToFastRope(_heli) - - if ctld.enableFastRopeInsertion == false then - return false - end - - --landed or speed is less than 8 km/h and height is less than fast rope height - if (ctld.inAir(_heli) == false or (ctld.heightDiff(_heli) <= ctld.fastRopeMaximumHeight + 3.0 and mist.vec.mag(_heli:getVelocity()) < 2.2)) then - return true - end -end - -function ctld.metersToFeet(_meters) - - local _feet = _meters * 3.2808399 - - return mist.utils.round(_feet) -end - -function ctld.inAir(_heli) - - if _heli:inAir() == false then - return false - end - - -- less than 5 cm/s a second so landed - -- BUT AI can hold a perfect hover so ignore AI - if mist.vec.mag(_heli:getVelocity()) < 0.05 and _heli:getPlayerName() ~= nil then - return false - end - return true -end - -function ctld.deployTroops(_heli, _troops) - - local _onboard = ctld.inTransitTroops[_heli:getName()] - - -- deloy troops - if _troops then - if _onboard.troops ~= nil and #_onboard.troops.units > 0 then - if ctld.inAir(_heli) == false or ctld.safeToFastRope(_heli) then - - -- check we're not in extract zone - local _extractZone = ctld.inExtractZone(_heli) - - if _extractZone == false then - - local _droppedTroops = ctld.spawnDroppedGroup(_heli:getPoint(), _onboard.troops, false) - ctld.logTrace(string.format("_onboard.troops=%s", ctld.p(_onboard.troops))) - if _onboard.troops.jtac or _droppedTroops:getName():lower():find("jtac") then - local _code = table.remove(ctld.jtacGeneratedLaserCodes, 1) - ctld.logTrace(string.format("_code=%s", ctld.p(_code))) - table.insert(ctld.jtacGeneratedLaserCodes, _code) - ctld.logTrace(string.format("_droppedTroops:getName()=%s", ctld.p(_droppedTroops:getName()))) - ctld.JTACAutoLase(_droppedTroops:getName(), _code) - end - - if _heli:getCoalition() == 1 then - - table.insert(ctld.droppedTroopsRED, _droppedTroops:getName()) - else - - table.insert(ctld.droppedTroopsBLUE, _droppedTroops:getName()) - end - - ctld.inTransitTroops[_heli:getName()].troops = nil - ctld.adaptWeightToCargo(_heli:getName()) - - if ctld.inAir(_heli) then - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " fast-ropped troops from " .. _heli:getTypeName() .. " into combat", 10) - else - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " dropped troops from " .. _heli:getTypeName() .. " into combat", 10) - end - - ctld.processCallback({unit = _heli, unloaded = _droppedTroops, action = "dropped_troops"}) - - - else - --extract zone! - local _droppedCount = trigger.misc.getUserFlag(_extractZone.flag) - - _droppedCount = (#_onboard.troops.units) + _droppedCount - - trigger.action.setUserFlag(_extractZone.flag, _droppedCount) - - ctld.inTransitTroops[_heli:getName()].troops = nil - ctld.adaptWeightToCargo(_heli:getName()) - - if ctld.inAir(_heli) then - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " troops fast-ropped from " .. _heli:getTypeName() .. " into " .. _extractZone.name, 10) - else - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " troops dropped from " .. _heli:getTypeName() .. " into " .. _extractZone.name, 10) - end - end - else - ctld.displayMessageToGroup(_heli, "Too high or too fast to drop troops into combat! Hover below " .. ctld.metersToFeet(ctld.fastRopeMaximumHeight) .. " feet or land.", 10) - end - end - - else - if ctld.inAir(_heli) == false then - if _onboard.vehicles ~= nil and #_onboard.vehicles.units > 0 then - - local _droppedVehicles = ctld.spawnDroppedGroup(_heli:getPoint(), _onboard.vehicles, true) - - if _heli:getCoalition() == 1 then - - table.insert(ctld.droppedVehiclesRED, _droppedVehicles:getName()) - else - - table.insert(ctld.droppedVehiclesBLUE, _droppedVehicles:getName()) - end - - ctld.inTransitTroops[_heli:getName()].vehicles = nil - ctld.adaptWeightToCargo(_heli:getName()) - - ctld.processCallback({unit = _heli, unloaded = _droppedVehicles, action = "dropped_vehicles"}) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " dropped vehicles from " .. _heli:getTypeName() .. " into combat", 10) - end - end - end -end - -function ctld.insertIntoTroopsArray(_troopType,_count,_troopArray,_troopName) - - for _i = 1, _count do - local _unitId = ctld.getNextUnitId() - table.insert(_troopArray, { type = _troopType, unitId = _unitId, name = string.format("Dropped %s #%i", _troopName or _troopType, _unitId) }) - end - - return _troopArray - -end - - -function ctld.generateTroopTypes(_side, _countOrTemplate, _country) - local _troops = {} - local _weight = 0 - local _hasJTAC = false - - local function getSoldiersWeight(count, additionalWeight) - local _weight = 0 - for i = 1, count do - local _soldierWeight = math.random(90, 120) * ctld.SOLDIER_WEIGHT / 100 - ctld.logTrace(string.format("_soldierWeight=%s", ctld.p(_soldierWeight))) - _weight = _weight + _soldierWeight + ctld.KIT_WEIGHT + additionalWeight - end - return _weight - end - - if type(_countOrTemplate) == "table" then - - if _countOrTemplate.aa then - ctld.logTrace(string.format("_countOrTemplate.aa=%s", ctld.p(_countOrTemplate.aa))) - if _side == 2 then - _troops = ctld.insertIntoTroopsArray("Soldier stinger",_countOrTemplate.aa,_troops) - else - _troops = ctld.insertIntoTroopsArray("SA-18 Igla manpad",_countOrTemplate.aa,_troops) - end - _weight = _weight + getSoldiersWeight(_countOrTemplate.aa, ctld.MANPAD_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - if _countOrTemplate.inf then - ctld.logTrace(string.format("_countOrTemplate.inf=%s", ctld.p(_countOrTemplate.inf))) - if _side == 2 then - _troops = ctld.insertIntoTroopsArray("Soldier M4",_countOrTemplate.inf,_troops) - else - _troops = ctld.insertIntoTroopsArray("Soldier AK",_countOrTemplate.inf,_troops) - end - _weight = _weight + getSoldiersWeight(_countOrTemplate.inf, ctld.RIFLE_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - if _countOrTemplate.mg then - ctld.logTrace(string.format("_countOrTemplate.mg=%s", ctld.p(_countOrTemplate.mg))) - if _side == 2 then - _troops = ctld.insertIntoTroopsArray("Soldier M249",_countOrTemplate.mg,_troops) - else - _troops = ctld.insertIntoTroopsArray("Paratrooper AKS-74",_countOrTemplate.mg,_troops) - end - _weight = _weight + getSoldiersWeight(_countOrTemplate.mg, ctld.MG_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - if _countOrTemplate.at then - ctld.logTrace(string.format("_countOrTemplate.at=%s", ctld.p(_countOrTemplate.at))) - _troops = ctld.insertIntoTroopsArray("Paratrooper RPG-16",_countOrTemplate.at,_troops) - _weight = _weight + getSoldiersWeight(_countOrTemplate.at, ctld.RPG_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - if _countOrTemplate.mortar then - ctld.logTrace(string.format("_countOrTemplate.mortar=%s", ctld.p(_countOrTemplate.mortar))) - _troops = ctld.insertIntoTroopsArray("2B11 mortar",_countOrTemplate.mortar,_troops) - _weight = _weight + getSoldiersWeight(_countOrTemplate.mortar, ctld.MORTAR_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - if _countOrTemplate.jtac then - ctld.logTrace(string.format("_countOrTemplate.jtac=%s", ctld.p(_countOrTemplate.jtac))) - if _side == 2 then - _troops = ctld.insertIntoTroopsArray("Soldier M4",_countOrTemplate.jtac,_troops, "JTAC") - else - _troops = ctld.insertIntoTroopsArray("Soldier AK",_countOrTemplate.jtac,_troops, "JTAC") - end - _hasJTAC = true - _weight = _weight + getSoldiersWeight(_countOrTemplate.jtac, ctld.JTAC_WEIGHT + ctld.RIFLE_WEIGHT) - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - end - - else - for _i = 1, _countOrTemplate do - - local _unitType = "Soldier AK" - - if _side == 2 then - if _i <=2 then - _unitType = "Soldier M249" - _weight = _weight + getSoldiersWeight(1, ctld.MG_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - elseif ctld.spawnRPGWithCoalition and _i > 2 and _i <= 4 then - _unitType = "Paratrooper RPG-16" - _weight = _weight + getSoldiersWeight(1, ctld.RPG_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - elseif ctld.spawnStinger and _i > 4 and _i <= 5 then - _unitType = "Soldier stinger" - _weight = _weight + getSoldiersWeight(1, ctld.MANPAD_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - else - _unitType = "Soldier M4" - _weight = _weight + getSoldiersWeight(1, ctld.RIFLE_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - end - else - if _i <=2 then - _unitType = "Paratrooper AKS-74" - _weight = _weight + getSoldiersWeight(1, ctld.MG_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - elseif ctld.spawnRPGWithCoalition and _i > 2 and _i <= 4 then - _unitType = "Paratrooper RPG-16" - _weight = _weight + getSoldiersWeight(1, ctld.RPG_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - elseif ctld.spawnStinger and _i > 4 and _i <= 5 then - _unitType = "SA-18 Igla manpad" - _weight = _weight + getSoldiersWeight(1, ctld.MANPAD_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - else - _unitType = "Infantry AK" - _weight = _weight + getSoldiersWeight(1, ctld.RIFLE_WEIGHT) - ctld.logTrace(string.format("_unitType=%s, _weight=%s", ctld.p(_unitType), ctld.p(_weight))) - end - end - - local _unitId = ctld.getNextUnitId() - - _troops[_i] = { type = _unitType, unitId = _unitId, name = string.format("Dropped %s #%i", _unitType, _unitId) } - end - end - - local _groupId = ctld.getNextGroupId() - local _groupName = "Dropped Group" - if _hasJTAC then - _groupName = "Dropped JTAC Group" - end - local _details = { units = _troops, groupId = _groupId, groupName = string.format("%s %i", _groupName, _groupId), side = _side, country = _country, weight = _weight, jtac = _hasJTAC } - ctld.logTrace(string.format("total weight=%s", ctld.p(_weight))) - - return _details -end - ---Special F10 function for players for troops -function ctld.unloadExtractTroops(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli == nil then - return false - end - - - local _extract = nil - if not ctld.inAir(_heli) then - if _heli:getCoalition() == 1 then - _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsRED) - else - _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsBLUE) - end - - end - - if _extract ~= nil and not ctld.troopsOnboard(_heli, true) then - -- search for nearest troops to pickup - return ctld.extractTroops({_heli:getName(), true}) - else - return ctld.unloadTroops({_heli:getName(),true,true}) - end - - -end - --- load troops onto vehicle -function ctld.loadTroops(_heli, _troops, _numberOrTemplate) - - -- load troops + vehicles if c130 or herc - -- "M1045 HMMWV TOW" - -- "M1043 HMMWV Armament" - local _onboard = ctld.inTransitTroops[_heli:getName()] - - --number doesnt apply to vehicles - if _numberOrTemplate == nil or (type(_numberOrTemplate) ~= "table" and type(_numberOrTemplate) ~= "number") then - _numberOrTemplate = ctld.getTransportLimit(_heli:getTypeName()) - end - - if _onboard == nil then - _onboard = { troops = {}, vehicles = {} } - end - - local _list - if _heli:getCoalition() == 1 then - _list = ctld.vehiclesForTransportRED - else - _list = ctld.vehiclesForTransportBLUE - end - - ctld.logTrace(string.format("_troops=%s", ctld.p(_troops))) - if _troops then - _onboard.troops = ctld.generateTroopTypes(_heli:getCoalition(), _numberOrTemplate, _heli:getCountry()) - ctld.logTrace(string.format("_onboard.troops=%s", ctld.p(_onboard.troops))) - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " loaded troops into " .. _heli:getTypeName(), 10) - - ctld.processCallback({unit = _heli, onboard = _onboard.troops, action = "load_troops"}) - else - - _onboard.vehicles = ctld.generateVehiclesForTransport(_heli:getCoalition(), _heli:getCountry()) - - local _count = #_list - - ctld.processCallback({unit = _heli, onboard = _onboard.vehicles, action = "load_vehicles"}) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " loaded " .. _count .. " vehicles into " .. _heli:getTypeName(), 10) - end - - ctld.inTransitTroops[_heli:getName()] = _onboard - ctld.logTrace(string.format("ctld.inTransitTroops=%s", ctld.p(ctld.inTransitTroops[_heli:getName()]))) - ctld.adaptWeightToCargo(_heli:getName()) -end - -function ctld.generateVehiclesForTransport(_side, _country) - - local _vehicles = {} - local _list - if _side == 1 then - _list = ctld.vehiclesForTransportRED - else - _list = ctld.vehiclesForTransportBLUE - end - - - for _i, _type in ipairs(_list) do - - local _unitId = ctld.getNextUnitId() - local _weight = ctld.vehiclesWeight[_type] or 2500 - _vehicles[_i] = { type = _type, unitId = _unitId, name = string.format("Dropped %s #%i", _type, _unitId), weight = _weight } - end - - - local _groupId = ctld.getNextGroupId() - local _details = { units = _vehicles, groupId = _groupId, groupName = string.format("Dropped Group %i", _groupId), side = _side, country = _country } - - return _details -end - -function ctld.loadUnloadFOBCrate(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _troops = _args[2] - - if _heli == nil then - return - end - - if ctld.inAir(_heli) == true then - return - end - - - local _side = _heli:getCoalition() - - local _inZone = ctld.inLogisticsZone(_heli) - local _crateOnboard = ctld.inTransitFOBCrates[_heli:getName()] ~= nil - - if _inZone == false and _crateOnboard == true then - - ctld.inTransitFOBCrates[_heli:getName()] = nil - - local _position = _heli:getPosition() - - --try to spawn at 6 oclock to us - local _angle = math.atan2(_position.x.z, _position.x.x) - local _xOffset = math.cos(_angle) * -60 - local _yOffset = math.sin(_angle) * -60 - - local _point = _heli:getPoint() - - local _side = _heli:getCoalition() - - local _unitId = ctld.getNextUnitId() - - local _name = string.format("FOB Crate #%i", _unitId) - - local _spawnedCrate = ctld.spawnFOBCrateStatic(_heli:getCountry(), ctld.getNextUnitId(), { x = _point.x + _xOffset, z = _point.z + _yOffset }, _name) - - if _side == 1 then - ctld.droppedFOBCratesRED[_name] = _name - else - ctld.droppedFOBCratesBLUE[_name] = _name - end - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " delivered a FOB Crate", 10) - - ctld.displayMessageToGroup(_heli, "Delivered FOB Crate 60m at 6'oclock to you", 10) - - elseif _inZone == true and _crateOnboard == true then - - ctld.displayMessageToGroup(_heli, "FOB Crate dropped back to base", 10) - - ctld.inTransitFOBCrates[_heli:getName()] = nil - - elseif _inZone == true and _crateOnboard == false then - ctld.displayMessageToGroup(_heli, "FOB Crate Loaded", 10) - - ctld.inTransitFOBCrates[_heli:getName()] = true - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " loaded a FOB Crate ready for delivery!", 10) - - else - - -- nearest Crate - local _crates = ctld.getCratesAndDistance(_heli) - local _nearestCrate = ctld.getClosestCrate(_heli, _crates, "FOB") - - if _nearestCrate ~= nil and _nearestCrate.dist < 150 then - - ctld.displayMessageToGroup(_heli, "FOB Crate Loaded", 10) - ctld.inTransitFOBCrates[_heli:getName()] = true - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " loaded a FOB Crate ready for delivery!", 10) - - if _side == 1 then - ctld.droppedFOBCratesRED[_nearestCrate.crateUnit:getName()] = nil - else - ctld.droppedFOBCratesBLUE[_nearestCrate.crateUnit:getName()] = nil - end - - --remove - _nearestCrate.crateUnit:destroy() - - else - ctld.displayMessageToGroup(_heli, "There are no friendly logistic units nearby to load a FOB crate from!", 10) - end - end -end - -function ctld.loadTroopsFromZone(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _troops = _args[2] - local _groupTemplate = _args[3] or "" - local _allowExtract = _args[4] - - if _heli == nil then - return false - end - - local _zone = ctld.inPickupZone(_heli) - - if ctld.troopsOnboard(_heli, _troops) then - - if _troops then - ctld.displayMessageToGroup(_heli, "You already have troops onboard.", 10) - else - ctld.displayMessageToGroup(_heli, "You already have vehicles onboard.", 10) - end - - return false - end - - local _extract - - if _allowExtract then - -- first check for extractable troops regardless of if we're in a zone or not - if _troops then - if _heli:getCoalition() == 1 then - _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsRED) - else - _extract = ctld.findNearestGroup(_heli, ctld.droppedTroopsBLUE) - end - else - - if _heli:getCoalition() == 1 then - _extract = ctld.findNearestGroup(_heli, ctld.droppedVehiclesRED) - else - _extract = ctld.findNearestGroup(_heli, ctld.droppedVehiclesBLUE) - end - end - end - - if _extract ~= nil then - -- search for nearest troops to pickup - return ctld.extractTroops({_heli:getName(), _troops}) - elseif _zone.inZone == true then - - if _zone.limit - 1 >= 0 then - -- decrease zone counter by 1 - ctld.updateZoneCounter(_zone.index, -1) - - ctld.loadTroops(_heli, _troops,_groupTemplate) - - return true - else - ctld.displayMessageToGroup(_heli, "This area has no more reinforcements available!", 20) - - return false - end - - else - if _allowExtract then - ctld.displayMessageToGroup(_heli, "You are not in a pickup zone and no one is nearby to extract", 10) - else - ctld.displayMessageToGroup(_heli, "You are not in a pickup zone", 10) - end - - return false - end -end - - - -function ctld.unloadTroops(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _troops = _args[2] - - if _heli == nil then - return false - end - - local _zone = ctld.inPickupZone(_heli) - if not ctld.troopsOnboard(_heli, _troops) then - - ctld.displayMessageToGroup(_heli, "No one to unload", 10) - - return false - else - - -- troops must be onboard to get here - if _zone.inZone == true then - - if _troops then - ctld.displayMessageToGroup(_heli, "Dropped troops back to base", 20) - - ctld.processCallback({unit = _heli, unloaded = ctld.inTransitTroops[_heli:getName()].troops, action = "unload_troops_zone"}) - - ctld.inTransitTroops[_heli:getName()].troops = nil - - else - ctld.displayMessageToGroup(_heli, "Dropped vehicles back to base", 20) - - ctld.processCallback({unit = _heli, unloaded = ctld.inTransitTroops[_heli:getName()].vehicles, action = "unload_vehicles_zone"}) - - ctld.inTransitTroops[_heli:getName()].vehicles = nil - end - - ctld.adaptWeightToCargo(_heli:getName()) - - -- increase zone counter by 1 - ctld.updateZoneCounter(_zone.index, 1) - - return true - - elseif ctld.troopsOnboard(_heli, _troops) then - - return ctld.deployTroops(_heli, _troops) - end - end - -end - -function ctld.extractTroops(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _troops = _args[2] - - if _heli == nil then - return false - end - - if ctld.inAir(_heli) then - return false - end - - if ctld.troopsOnboard(_heli, _troops) then - if _troops then - ctld.displayMessageToGroup(_heli, "You already have troops onboard.", 10) - else - ctld.displayMessageToGroup(_heli, "You already have vehicles onboard.", 10) - end - - return false - end - - local _onboard = ctld.inTransitTroops[_heli:getName()] - - if _onboard == nil then - _onboard = { troops = nil, vehicles = nil } - end - - local _extracted = false - - if _troops then - - local _extractTroops - - if _heli:getCoalition() == 1 then - _extractTroops = ctld.findNearestGroup(_heli, ctld.droppedTroopsRED) - else - _extractTroops = ctld.findNearestGroup(_heli, ctld.droppedTroopsBLUE) - end - - - if _extractTroops ~= nil then - - local _limit = ctld.getTransportLimit(_heli:getTypeName()) - - local _size = #_extractTroops.group:getUnits() - - if _limit < #_extractTroops.group:getUnits() then - - ctld.displayMessageToGroup(_heli, "Sorry - The group of ".._size.." is too large to fit. \n\nLimit is ".._limit.." for ".._heli:getTypeName(), 20) - - return - end - - _onboard.troops = _extractTroops.details - _onboard.troops.weight = #_extractTroops.group:getUnits() * 130 -- default to 130kg per soldier - - if _extractTroops.group:getName():lower():find("jtac") then - _onboard.troops.jtac = true - end - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " extracted troops in " .. _heli:getTypeName() .. " from combat", 10) - - if _heli:getCoalition() == 1 then - ctld.droppedTroopsRED[_extractTroops.group:getName()] = nil - else - ctld.droppedTroopsBLUE[_extractTroops.group:getName()] = nil - end - - ctld.processCallback({unit = _heli, extracted = _extractTroops, action = "extract_troops"}) - - --remove - _extractTroops.group:destroy() - - _extracted = true - else - _onboard.troops = nil - ctld.displayMessageToGroup(_heli, "No extractable troops nearby!", 20) - end - - else - - local _extractVehicles - - - if _heli:getCoalition() == 1 then - - _extractVehicles = ctld.findNearestGroup(_heli, ctld.droppedVehiclesRED) - else - - _extractVehicles = ctld.findNearestGroup(_heli, ctld.droppedVehiclesBLUE) - end - - if _extractVehicles ~= nil then - _onboard.vehicles = _extractVehicles.details - - if _heli:getCoalition() == 1 then - - ctld.droppedVehiclesRED[_extractVehicles.group:getName()] = nil - else - - ctld.droppedVehiclesBLUE[_extractVehicles.group:getName()] = nil - end - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " extracted vehicles in " .. _heli:getTypeName() .. " from combat", 10) - - ctld.processCallback({unit = _heli, extracted = _extractVehicles, action = "extract_vehicles"}) - --remove - _extractVehicles.group:destroy() - _extracted = true - - else - _onboard.vehicles = nil - ctld.displayMessageToGroup(_heli, "No extractable vehicles nearby!", 20) - end - end - - ctld.inTransitTroops[_heli:getName()] = _onboard - ctld.adaptWeightToCargo(_heli:getName()) - - return _extracted -end - - -function ctld.checkTroopStatus(_args) - local _unitName = _args[1] - --list onboard troops, if c130 - local _heli = ctld.getTransportUnit(_unitName) - - if _heli == nil then - return - end - - local _, _message = ctld.getWeightOfCargo(_unitName) - ctld.logTrace(string.format("_message=%s", ctld.p(_message))) - if _message and _message ~= "" then - ctld.displayMessageToGroup(_heli, _message, 10) - end -end - --- Removes troops from transport when it dies -function ctld.checkTransportStatus() - - timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 3) - - for _, _name in ipairs(ctld.transportPilotNames) do - - local _transUnit = ctld.getTransportUnit(_name) - - if _transUnit == nil then - --env.info("CTLD Transport Unit Dead event") - ctld.inTransitTroops[_name] = nil - ctld.inTransitFOBCrates[_name] = nil - ctld.inTransitSlingLoadCrates[_name] = nil - end - end -end - -function ctld.adaptWeightToCargo(unitName) - local _weight = ctld.getWeightOfCargo(unitName) - trigger.action.setUnitInternalCargo(unitName, _weight) -end - -function ctld.getWeightOfCargo(unitName) - ctld.logDebug(string.format("ctld.getWeightOfCargo(%s)", ctld.p(unitName))) - - local FOB_CRATE_WEIGHT = 800 - local _weight = 0 - local _description = "" - - -- add troops weight - if ctld.inTransitTroops[unitName] then - ctld.logTrace("ctld.inTransitTroops = true") - local _inTransit = ctld.inTransitTroops[unitName] - if _inTransit then - ctld.logTrace(string.format("_inTransit=%s", ctld.p(_inTransit))) - local _troops = _inTransit.troops - if _troops and _troops.units then - ctld.logTrace(string.format("_troops.weight=%s", ctld.p(_troops.weight))) - _description = _description .. string.format("%s troops onboard (%s kg)\n", #_troops.units, _troops.weight) - _weight = _weight + _troops.weight - end - local _vehicles = _inTransit.vehicles - if _vehicles and _vehicles.units then - for _, _unit in pairs(_vehicles.units) do - _weight = _weight + _unit.weight - end - ctld.logTrace(string.format("_weight=%s", ctld.p(_weight))) - _description = _description .. string.format("%s vehicles onboard (%s kg)\n", #_vehicles.units, _weight) - end - end - end - ctld.logTrace(string.format("with troops and vehicles : weight = %s", tostring(_weight))) - - -- add FOB crates weight - if ctld.inTransitFOBCrates[unitName] then - ctld.logTrace("ctld.inTransitFOBCrates = true") - _weight = _weight + FOB_CRATE_WEIGHT - _description = _description .. string.format("1 FOB Crate oboard (%s kg)\n", FOB_CRATE_WEIGHT) - end - ctld.logTrace(string.format("with FOB crates : weight = %s", tostring(_weight))) - - -- add simulated slingload crates weight - local _crate = ctld.inTransitSlingLoadCrates[unitName] - if _crate then - ctld.logTrace(string.format("_crate=%s", ctld.p(_crate))) - if _crate.simulatedSlingload then - ctld.logTrace(string.format("_crate.weight=%s", ctld.p(_crate.weight))) - _weight = _weight + _crate.weight - _description = _description .. string.format("1 %s crate onboard (%s kg)\n", _crate.desc, _crate.weight) - end - end - ctld.logTrace(string.format("with simulated slingload crates : weight = %s", tostring(_weight))) - if _description ~= "" then - _description = _description .. string.format("Total weight of cargo : %s kg\n", _weight) - else - _description = "No cargo." - end - ctld.logTrace(string.format("_description = %s", tostring(_description))) - - return _weight, _description -end - -function ctld.checkHoverStatus() - --ctld.logDebug(string.format("ctld.checkHoverStatus()")) - timer.scheduleFunction(ctld.checkHoverStatus, nil, timer.getTime() + 1.0) - - local _status, _result = pcall(function() - - for _, _name in ipairs(ctld.transportPilotNames) do - - local _reset = true - local _transUnit = ctld.getTransportUnit(_name) - - --only check transports that are hovering and not planes - if _transUnit ~= nil and ctld.inTransitSlingLoadCrates[_name] == nil and ctld.inAir(_transUnit) and ctld.unitCanCarryVehicles(_transUnit) == false then - - --ctld.logTrace(string.format("%s - capable of slingloading", ctld.p(_name))) - - local _crates = ctld.getCratesAndDistance(_transUnit) - --ctld.logTrace(string.format("_crates = %s", ctld.p(_crates))) - - for _, _crate in pairs(_crates) do - --ctld.logTrace(string.format("_crate = %s", ctld.p(_crate))) - if _crate.dist < ctld.maxDistanceFromCrate and _crate.details.unit ~= "FOB" then - - --check height! - local _height = _transUnit:getPoint().y - _crate.crateUnit:getPoint().y - --env.info("HEIGHT " .. _name .. " " .. _height .. " " .. _transUnit:getPoint().y .. " " .. _crate.crateUnit:getPoint().y) - -- ctld.heightDiff(_transUnit) - --env.info("HEIGHT ABOVE GROUD ".._name.." ".._height.." ".._transUnit:getPoint().y.." ".._crate.crateUnit:getPoint().y) - --ctld.logTrace(string.format("_height = %s", ctld.p(_height))) - - if _height > ctld.minimumHoverHeight and _height <= ctld.maximumHoverHeight then - - local _time = ctld.hoverStatus[_transUnit:getName()] - --ctld.logTrace(string.format("_time = %s", ctld.p(_time))) - - if _time == nil then - ctld.hoverStatus[_transUnit:getName()] = ctld.hoverTime - _time = ctld.hoverTime - else - _time = ctld.hoverStatus[_transUnit:getName()] - 1 - ctld.hoverStatus[_transUnit:getName()] = _time - end - - if _time > 0 then - ctld.displayMessageToGroup(_transUnit, "Hovering above " .. _crate.details.desc .. " crate. \n\nHold hover for " .. _time .. " seconds! \n\nIf the countdown stops you're too far away!", 10,true) - else - ctld.hoverStatus[_transUnit:getName()] = nil - ctld.displayMessageToGroup(_transUnit, "Loaded " .. _crate.details.desc .. " crate!", 10,true) - - --crates been moved once! - ctld.crateMove[_crate.crateUnit:getName()] = nil - - if _transUnit:getCoalition() == 1 then - ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil - end - - _crate.crateUnit:destroy() - - local _copiedCrate = mist.utils.deepCopy(_crate.details) - _copiedCrate.simulatedSlingload = true - --ctld.logTrace(string.format("_copiedCrate = %s", ctld.p(_copiedCrate))) - ctld.inTransitSlingLoadCrates[_name] = _copiedCrate - ctld.adaptWeightToCargo(_name) - end - - _reset = false - - break - elseif _height <= ctld.minimumHoverHeight then - ctld.displayMessageToGroup(_transUnit, "Too low to hook " .. _crate.details.desc .. " crate.\n\nHold hover for " .. ctld.hoverTime .. " seconds", 5,true) - break - else - ctld.displayMessageToGroup(_transUnit, "Too high to hook " .. _crate.details.desc .. " crate.\n\nHold hover for " .. ctld.hoverTime .. " seconds", 5, true) - break - end - end - end - end - - if _reset then - ctld.hoverStatus[_name] = nil - end - end - end) - - if (not _status) then - env.error(string.format("CTLD ERROR: %s", _result)) - end -end - -function ctld.loadNearbyCrate(_name) - local _transUnit = ctld.getTransportUnit(_name) - - if _transUnit ~= nil then - - if ctld.inAir(_transUnit) then - ctld.displayMessageToGroup(_transUnit, "You must land before you can load a crate!", 10,true) - return - end - - if ctld.inTransitSlingLoadCrates[_name] == nil then - local _crates = ctld.getCratesAndDistance(_transUnit) - - for _, _crate in pairs(_crates) do - - if _crate.dist < 50.0 then - ctld.displayMessageToGroup(_transUnit, "Loaded " .. _crate.details.desc .. " crate!", 10,true) - - if _transUnit:getCoalition() == 1 then - ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil - end - - ctld.crateMove[_crate.crateUnit:getName()] = nil - - _crate.crateUnit:destroy() - - local _copiedCrate = mist.utils.deepCopy(_crate.details) - _copiedCrate.simulatedSlingload = true - ctld.inTransitSlingLoadCrates[_name] = _copiedCrate - ctld.adaptWeightToCargo(_name) - return - end - end - - ctld.displayMessageToGroup(_transUnit, "No Crates within 50m to load!", 10,true) - - else - -- crate onboard - ctld.displayMessageToGroup(_transUnit, "You already have a "..ctld.inTransitSlingLoadCrates[_name].desc.." crate onboard!", 10,true) - end - end - - -end - ---recreates beacons to make sure they work! -function ctld.refreshRadioBeacons() - - timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 30) - - - for _index, _beaconDetails in ipairs(ctld.deployedRadioBeacons) do - - --trigger.action.outTextForCoalition(_beaconDetails.coalition,_beaconDetails.text,10) - if ctld.updateRadioBeacon(_beaconDetails) == false then - - --search used frequencies + remove, add back to unused - - for _i, _freq in ipairs(ctld.usedUHFFrequencies) do - if _freq == _beaconDetails.uhf then - - table.insert(ctld.freeUHFFrequencies, _freq) - table.remove(ctld.usedUHFFrequencies, _i) - end - end - - for _i, _freq in ipairs(ctld.usedVHFFrequencies) do - if _freq == _beaconDetails.vhf then - - table.insert(ctld.freeVHFFrequencies, _freq) - table.remove(ctld.usedVHFFrequencies, _i) - end - end - - for _i, _freq in ipairs(ctld.usedFMFrequencies) do - if _freq == _beaconDetails.fm then - - table.insert(ctld.freeFMFrequencies, _freq) - table.remove(ctld.usedFMFrequencies, _i) - end - end - - --clean up beacon table - table.remove(ctld.deployedRadioBeacons, _index) - end - end -end - -function ctld.getClockDirection(_heli, _crate) - - -- Source: Helicopter Script - Thanks! - - local _position = _crate:getPosition().p -- get position of crate - local _playerPosition = _heli:getPosition().p -- get position of helicopter - local _relativePosition = mist.vec.sub(_position, _playerPosition) - - local _playerHeading = mist.getHeading(_heli) -- the rest of the code determines the 'o'clock' bearing of the missile relative to the helicopter - - local _headingVector = { x = math.cos(_playerHeading), y = 0, z = math.sin(_playerHeading) } - - local _headingVectorPerpendicular = { x = math.cos(_playerHeading + math.pi / 2), y = 0, z = math.sin(_playerHeading + math.pi / 2) } - - local _forwardDistance = mist.vec.dp(_relativePosition, _headingVector) - - local _rightDistance = mist.vec.dp(_relativePosition, _headingVectorPerpendicular) - - local _angle = math.atan2(_rightDistance, _forwardDistance) * 180 / math.pi - - if _angle < 0 then - _angle = 360 + _angle - end - _angle = math.floor(_angle * 12 / 360 + 0.5) - if _angle == 0 then - _angle = 12 - end - - return _angle -end - - -function ctld.getCompassBearing(_ref, _unitPos) - - _ref = mist.utils.makeVec3(_ref, 0) -- turn it into Vec3 if it is not already. - _unitPos = mist.utils.makeVec3(_unitPos, 0) -- turn it into Vec3 if it is not already. - - local _vec = { x = _unitPos.x - _ref.x, y = _unitPos.y - _ref.y, z = _unitPos.z - _ref.z } - - local _dir = mist.utils.getDir(_vec, _ref) - - local _bearing = mist.utils.round(mist.utils.toDegree(_dir), 0) - - return _bearing -end - -function ctld.listNearbyCrates(_args) - - local _message = "" - - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli == nil then - - return -- no heli! - end - - local _crates = ctld.getCratesAndDistance(_heli) - - --sort - local _sort = function( a,b ) return a.dist < b.dist end - table.sort(_crates,_sort) - - for _, _crate in pairs(_crates) do - - if _crate.dist < 1000 and _crate.details.unit ~= "FOB" then - _message = string.format("%s\n%s crate - kg %i - %i m - %d o'clock", _message, _crate.details.desc, _crate.details.weight, _crate.dist, ctld.getClockDirection(_heli, _crate.crateUnit)) - end - end - - - local _fobMsg = "" - for _, _fobCrate in pairs(_crates) do - - if _fobCrate.dist < 1000 and _fobCrate.details.unit == "FOB" then - _fobMsg = _fobMsg .. string.format("FOB Crate - %d m - %d o'clock\n", _fobCrate.dist, ctld.getClockDirection(_heli, _fobCrate.crateUnit)) - end - end - - if _message ~= "" or _fobMsg ~= "" then - - local _txt = "" - - if _message ~= "" then - _txt = "Nearby Crates:\n" .. _message - end - - if _fobMsg ~= "" then - - if _message ~= "" then - _txt = _txt .. "\n\n" - end - - _txt = _txt .. "Nearby FOB Crates (Not Slingloadable):\n" .. _fobMsg - end - - ctld.displayMessageToGroup(_heli, _txt, 20) - - else - --no crates nearby - - local _txt = "No Nearby Crates" - - ctld.displayMessageToGroup(_heli, _txt, 20) - end -end - - -function ctld.listFOBS(_args) - - local _msg = "FOB Positions:" - - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli == nil then - - return -- no heli! - end - - -- get fob positions - - local _fobs = ctld.getSpawnedFobs(_heli) - - -- now check spawned fobs - for _, _fob in ipairs(_fobs) do - _msg = string.format("%s\nFOB @ %s", _msg, ctld.getFOBPositionString(_fob)) - end - - if _msg == "FOB Positions:" then - ctld.displayMessageToGroup(_heli, "Sorry, there are no active FOBs!", 20) - else - ctld.displayMessageToGroup(_heli, _msg, 20) - end -end - -function ctld.getFOBPositionString(_fob) - - local _lat, _lon = coord.LOtoLL(_fob:getPosition().p) - - local _latLngStr = mist.tostringLL(_lat, _lon, 3, ctld.location_DMS) - - -- local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_fob:getPosition().p)), 5) - - local _message = _latLngStr - - local _beaconInfo = ctld.fobBeacons[_fob:getName()] - - if _beaconInfo ~= nil then - _message = string.format("%s - %.2f KHz ", _message, _beaconInfo.vhf / 1000) - _message = string.format("%s - %.2f MHz ", _message, _beaconInfo.uhf / 1000000) - _message = string.format("%s - %.2f MHz ", _message, _beaconInfo.fm / 1000000) - end - - return _message -end - - -function ctld.displayMessageToGroup(_unit, _text, _time,_clear) - - local _groupId = ctld.getGroupId(_unit) - if _groupId then - if _clear == true then - trigger.action.outTextForGroup(_groupId, _text, _time,_clear) - else - trigger.action.outTextForGroup(_groupId, _text, _time) - end - end -end - -function ctld.heightDiff(_unit) - - local _point = _unit:getPoint() - - -- env.info("heightunit " .. _point.y) - --env.info("heightland " .. land.getHeight({ x = _point.x, y = _point.z })) - - return _point.y - land.getHeight({ x = _point.x, y = _point.z }) -end - ---includes fob crates! -function ctld.getCratesAndDistance(_heli) - - local _crates = {} - - local _allCrates - if _heli:getCoalition() == 1 then - _allCrates = ctld.spawnedCratesRED - else - _allCrates = ctld.spawnedCratesBLUE - end - - for _crateName, _details in pairs(_allCrates) do - - --get crate - local _crate = ctld.getCrateObject(_crateName) - - --in air seems buggy with crates so if in air is true, get the height above ground and the speed magnitude - if _crate ~= nil and _crate:getLife() > 0 - and (ctld.inAir(_crate) == false) then - - local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint()) - - local _crateDetails = { crateUnit = _crate, dist = _dist, details = _details } - - table.insert(_crates, _crateDetails) - end - end - - local _fobCrates - if _heli:getCoalition() == 1 then - _fobCrates = ctld.droppedFOBCratesRED - else - _fobCrates = ctld.droppedFOBCratesBLUE - end - - for _crateName, _details in pairs(_fobCrates) do - - --get crate - local _crate = ctld.getCrateObject(_crateName) - - if _crate ~= nil and _crate:getLife() > 0 then - - local _dist = ctld.getDistance(_crate:getPoint(), _heli:getPoint()) - - local _crateDetails = { crateUnit = _crate, dist = _dist, details = { unit = "FOB" }, } - - table.insert(_crates, _crateDetails) - end - end - - return _crates -end - - -function ctld.getClosestCrate(_heli, _crates, _type) - - local _closetCrate = nil - local _shortestDistance = -1 - local _distance = 0 - - for _, _crate in pairs(_crates) do - - if (_crate.details.unit == _type or _type == nil) then - _distance = _crate.dist - - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - _closetCrate = _crate - end - end - end - - return _closetCrate -end - -function ctld.findNearestAASystem(_heli,_aaSystem) - - local _closestHawkGroup = nil - local _shortestDistance = -1 - local _distance = 0 - - for _groupName, _hawkDetails in pairs(ctld.completeAASystems) do - - local _hawkGroup = Group.getByName(_groupName) - - -- env.info(_groupName..": "..mist.utils.tableShow(_hawkDetails)) - if _hawkGroup ~= nil and _hawkGroup:getCoalition() == _heli:getCoalition() and _hawkDetails[1].system.name == _aaSystem.name then - - local _units = _hawkGroup:getUnits() - - for _, _leader in pairs(_units) do - - if _leader ~= nil and _leader:getLife() > 0 then - - _distance = ctld.getDistance(_leader:getPoint(), _heli:getPoint()) - - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - _closestHawkGroup = _hawkGroup - end - - break - end - end - end - end - - if _closestHawkGroup ~= nil then - - return { group = _closestHawkGroup, dist = _shortestDistance } - end - return nil -end - -function ctld.getCrateObject(_name) - local _crate - - if ctld.staticBugWorkaround then - _crate = Unit.getByName(_name) - else - _crate = StaticObject.getByName(_name) - end - return _crate -end - - - -function ctld.unpackCrates(_arguments) - - local _status, _err = pcall(function(_args) - - -- trigger.action.outText("Unpack Crates".._args[1],10) - - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli ~= nil and ctld.inAir(_heli) == false then - - local _crates = ctld.getCratesAndDistance(_heli) - local _crate = ctld.getClosestCrate(_heli, _crates) - - - if ctld.inLogisticsZone(_heli) == true or ctld.farEnoughFromLogisticZone(_heli) == false then - - ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20) - - return - end - - - - if _crate ~= nil and _crate.dist < 750 - and (_crate.details.unit == "FOB" or _crate.details.unit == "FOB-SMALL") then - - ctld.unpackFOBCrates(_crates, _heli) - - return - - elseif _crate ~= nil and _crate.dist < 200 then - - if ctld.forceCrateToBeMoved and ctld.crateMove[_crate.crateUnit:getName()] then - ctld.displayMessageToGroup(_heli,"Sorry you must move this crate before you unpack it!", 20) - return - end - - - local _aaTemplate = ctld.getAATemplate(_crate.details.unit) - - if _aaTemplate then - - if _crate.details.unit == _aaTemplate.repair then - ctld.repairAASystem(_heli, _crate,_aaTemplate) - else - ctld.unpackAASystem(_heli, _crate, _crates,_aaTemplate) - end - - return -- stop processing - -- is multi crate? - elseif _crate.details.cratesRequired ~= nil and _crate.details.cratesRequired > 1 then - -- multicrate - - ctld.unpackMultiCrate(_heli, _crate, _crates) - - return - - else - -- single crate - local _cratePoint = _crate.crateUnit:getPoint() - local _crateName = _crate.crateUnit:getName() - - -- ctld.spawnCrateStatic( _heli:getCoalition(),ctld.getNextUnitId(),{x=100,z=100},_crateName,100) - - --remove crate - -- if ctld.slingLoad == false then - _crate.crateUnit:destroy() - -- end - - local _spawnedGroups = ctld.spawnCrateGroup(_heli, { _cratePoint }, { _crate.details.unit }) - - if _heli:getCoalition() == 1 then - ctld.spawnedCratesRED[_crateName] = nil - else - ctld.spawnedCratesBLUE[_crateName] = nil - end - - ctld.processCallback({unit = _heli, crate = _crate , spawnedGroup = _spawnedGroups, action = "unpack"}) - - if _crate.details.unit == "1L13 EWR" then - ctld.addEWRTask(_spawnedGroups) - - -- env.info("Added EWR") - end - - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully deployed " .. _crate.details.desc .. " to the field", 10) - - if ctld.isJTACUnitType(_crate.details.unit) and ctld.JTAC_dropEnabled then - - local _code = table.remove(ctld.jtacGeneratedLaserCodes, 1) - --put to the end - table.insert(ctld.jtacGeneratedLaserCodes, _code) - - ctld.JTACAutoLase(_spawnedGroups:getName(), _code) --(_jtacGroupName, _laserCode, _smoke, _lock, _colour) - end - end - - else - - ctld.displayMessageToGroup(_heli, "No friendly crates close enough to unpack", 20) - end - end - end, _arguments) - - if (not _status) then - env.error(string.format("CTLD ERROR: %s", _err)) - end -end - - --- builds a fob! -function ctld.unpackFOBCrates(_crates, _heli) - - if ctld.inLogisticsZone(_heli) == true then - - ctld.displayMessageToGroup(_heli, "You can't unpack that here! Take it to where it's needed!", 20) - - return - end - - -- unpack multi crate - local _nearbyMultiCrates = {} - - local _bigFobCrates = 0 - local _smallFobCrates = 0 - local _totalCrates = 0 - - for _, _nearbyCrate in pairs(_crates) do - - if _nearbyCrate.dist < 750 then - - if _nearbyCrate.details.unit == "FOB" then - _bigFobCrates = _bigFobCrates + 1 - table.insert(_nearbyMultiCrates, _nearbyCrate) - elseif _nearbyCrate.details.unit == "FOB-SMALL" then - _smallFobCrates = _smallFobCrates + 1 - table.insert(_nearbyMultiCrates, _nearbyCrate) - end - - --catch divide by 0 - if _smallFobCrates > 0 then - _totalCrates = _bigFobCrates + (_smallFobCrates/3.0) - else - _totalCrates = _bigFobCrates - end - - if _totalCrates >= ctld.cratesRequiredForFOB then - break - end - end - end - - --- check crate count - if _totalCrates >= ctld.cratesRequiredForFOB then - - -- destroy crates - - local _points = {} - - for _, _crate in pairs(_nearbyMultiCrates) do - - if _heli:getCoalition() == 1 then - ctld.droppedFOBCratesRED[_crate.crateUnit:getName()] = nil - ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil - else - ctld.droppedFOBCratesBLUE[_crate.crateUnit:getName()] = nil - ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil - end - - table.insert(_points, _crate.crateUnit:getPoint()) - - --destroy - _crate.crateUnit:destroy() - end - - local _centroid = ctld.getCentroid(_points) - - timer.scheduleFunction(function(_args) - - local _unitId = ctld.getNextUnitId() - local _name = "Deployed FOB #" .. _unitId - - local _fob = ctld.spawnFOB(_args[2], _unitId, _args[1], _name) - - --make it able to deploy crates - table.insert(ctld.logisticUnits, _fob:getName()) - - ctld.beaconCount = ctld.beaconCount + 1 - - local _radioBeaconName = "FOB Beacon #" .. ctld.beaconCount - - local _radioBeaconDetails = ctld.createRadioBeacon(_args[1], _args[3], _args[2], _radioBeaconName, nil, true) - - ctld.fobBeacons[_name] = { vhf = _radioBeaconDetails.vhf, uhf = _radioBeaconDetails.uhf, fm = _radioBeaconDetails.fm } - - if ctld.troopPickupAtFOB == true then - table.insert(ctld.builtFOBS, _fob:getName()) - - trigger.action.outTextForCoalition(_args[3], "Finished building FOB! Crates and Troops can now be picked up.", 10) - else - trigger.action.outTextForCoalition(_args[3], "Finished building FOB! Crates can now be picked up.", 10) - end - end, { _centroid, _heli:getCountry(), _heli:getCoalition() }, timer.getTime() + ctld.buildTimeFOB) - - local _txt = string.format("%s started building FOB using %d FOB crates, it will be finished in %d seconds.\nPosition marked with smoke.", ctld.getPlayerNameOrType(_heli), _totalCrates, ctld.buildTimeFOB) - - ctld.processCallback({unit = _heli, position = _centroid, action = "fob"}) - - trigger.action.smoke(_centroid, trigger.smokeColor.Green) - - trigger.action.outTextForCoalition(_heli:getCoalition(), _txt, 10) - else - local _txt = string.format("Cannot build FOB!\n\nIt requires %d Large FOB crates ( 3 small FOB crates equal 1 large FOB Crate) and there are the equivalent of %d large FOB crates nearby\n\nOr the crates are not within 750m of each other", ctld.cratesRequiredForFOB, _totalCrates) - ctld.displayMessageToGroup(_heli, _txt, 20) - end -end - ---unloads the sling crate when the helicopter is on the ground or between 4.5 - 10 meters -function ctld.dropSlingCrate(_args) - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli == nil then - return -- no heli! - end - - local _currentCrate = ctld.inTransitSlingLoadCrates[_heli:getName()] - - if _currentCrate == nil then - if ctld.hoverPickup then - ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate, hover for "..ctld.hoverTime.." seconds above the crate", 10) - else - ctld.displayMessageToGroup(_heli, "You are not currently transporting any crates. \n\nTo Pickup a crate - land and use F10 Crate Commands to load one.", 10) - end - else - - local _heli = ctld.getTransportUnit(_args[1]) - - local _point = _heli:getPoint() - - local _unitId = ctld.getNextUnitId() - - local _side = _heli:getCoalition() - - local _name = string.format("%s #%i", _currentCrate.desc, _unitId) - - - local _heightDiff = ctld.heightDiff(_heli) - - if ctld.inAir(_heli) == false or _heightDiff <= 7.5 then - ctld.displayMessageToGroup(_heli, _currentCrate.desc .. " crate has been safely unhooked and is at your 12 o'clock", 10) - _point = ctld.getPointAt12Oclock(_heli, 30) - -- elseif _heightDiff > 40.0 then - -- ctld.inTransitSlingLoadCrates[_heli:getName()] = nil - -- ctld.displayMessageToGroup(_heli, "You were too high! The crate has been destroyed", 10) - -- return - elseif _heightDiff > 7.5 and _heightDiff <= 40.0 then - ctld.displayMessageToGroup(_heli, _currentCrate.desc .. " crate has been safely dropped below you", 10) - else -- _heightDiff > 40.0 - ctld.inTransitSlingLoadCrates[_heli:getName()] = nil - ctld.displayMessageToGroup(_heli, "You were too high! The crate has been destroyed", 10) - return - end - - - --remove crate from cargo - ctld.inTransitSlingLoadCrates[_heli:getName()] = nil - ctld.adaptWeightToCargo(_heli:getName()) - local _spawnedCrate = ctld.spawnCrateStatic(_heli:getCountry(), _unitId, _point, _name, _currentCrate.weight,_side) - end -end - ---spawns a radio beacon made up of two units, --- one for VHF and one for UHF --- The units are set to to NOT engage -function ctld.createRadioBeacon(_point, _coalition, _country, _name, _batteryTime, _isFOB) - - local _uhfGroup = ctld.spawnRadioBeaconUnit(_point, _country, "UHF") - local _vhfGroup = ctld.spawnRadioBeaconUnit(_point, _country, "VHF") - local _fmGroup = ctld.spawnRadioBeaconUnit(_point, _country, "FM") - - local _freq = ctld.generateADFFrequencies() - - --create timeout - local _battery - - if _batteryTime == nil then - _battery = timer.getTime() + (ctld.deployedBeaconBattery * 60) - else - _battery = timer.getTime() + (_batteryTime * 60) - end - - local _lat, _lon = coord.LOtoLL(_point) - - local _latLngStr = mist.tostringLL(_lat, _lon, 3, ctld.location_DMS) - - --local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_point)), 5) - - local _message = _name - - if _isFOB then - -- _message = "FOB " .. _message - _battery = -1 --never run out of power! - end - - _message = _message .. " - " .. _latLngStr - - -- env.info("GEN UHF: ".. _freq.uhf) - -- env.info("GEN VHF: ".. _freq.vhf) - - _message = string.format("%s - %.2f KHz", _message, _freq.vhf / 1000) - - _message = string.format("%s - %.2f MHz", _message, _freq.uhf / 1000000) - - _message = string.format("%s - %.2f MHz ", _message, _freq.fm / 1000000) - - - - local _beaconDetails = { - vhf = _freq.vhf, - vhfGroup = _vhfGroup:getName(), - uhf = _freq.uhf, - uhfGroup = _uhfGroup:getName(), - fm = _freq.fm, - fmGroup = _fmGroup:getName(), - text = _message, - battery = _battery, - coalition = _coalition, - } - ctld.updateRadioBeacon(_beaconDetails) - - table.insert(ctld.deployedRadioBeacons, _beaconDetails) - - return _beaconDetails -end - -function ctld.generateADFFrequencies() - - if #ctld.freeUHFFrequencies <= 3 then - ctld.freeUHFFrequencies = ctld.usedUHFFrequencies - ctld.usedUHFFrequencies = {} - end - - --remove frequency at RANDOM - local _uhf = table.remove(ctld.freeUHFFrequencies, math.random(#ctld.freeUHFFrequencies)) - table.insert(ctld.usedUHFFrequencies, _uhf) - - - if #ctld.freeVHFFrequencies <= 3 then - ctld.freeVHFFrequencies = ctld.usedVHFFrequencies - ctld.usedVHFFrequencies = {} - end - - local _vhf = table.remove(ctld.freeVHFFrequencies, math.random(#ctld.freeVHFFrequencies)) - table.insert(ctld.usedVHFFrequencies, _vhf) - - if #ctld.freeFMFrequencies <= 3 then - ctld.freeFMFrequencies = ctld.usedFMFrequencies - ctld.usedFMFrequencies = {} - end - - local _fm = table.remove(ctld.freeFMFrequencies, math.random(#ctld.freeFMFrequencies)) - table.insert(ctld.usedFMFrequencies, _fm) - - return { uhf = _uhf, vhf = _vhf, fm = _fm } - --- return {uhf=_uhf,vhf=_vhf} -end - - - -function ctld.spawnRadioBeaconUnit(_point, _country, _type) - - local _groupId = ctld.getNextGroupId() - - local _unitId = ctld.getNextUnitId() - - local _radioGroup = { - ["visible"] = false, - -- ["groupId"] = _groupId, - ["hidden"] = false, - ["units"] = { - [1] = { - ["y"] = _point.z, - ["type"] = "TACAN_beacon", - ["name"] = _type .. " Radio Beacon Unit #" .. _unitId, - -- ["unitId"] = _unitId, - ["heading"] = 0, - ["playerCanDrive"] = true, - ["skill"] = "Excellent", - ["x"] = _point.x, - } - }, - -- ["y"] = _positions[1].z, - -- ["x"] = _positions[1].x, - ["name"] = _type .. " Radio Beacon Group #" .. _groupId, - ["task"] = {}, - --added two fields below for MIST - ["category"] = Group.Category.GROUND, - ["country"] = _country - } - - -- return coalition.addGroup(_country, Group.Category.GROUND, _radioGroup) - return Group.getByName(mist.dynAdd(_radioGroup).name) -end - -function ctld.updateRadioBeacon(_beaconDetails) - - local _vhfGroup = Group.getByName(_beaconDetails.vhfGroup) - - local _uhfGroup = Group.getByName(_beaconDetails.uhfGroup) - - local _fmGroup = Group.getByName(_beaconDetails.fmGroup) - - local _radioLoop = {} - - if _vhfGroup ~= nil and _vhfGroup:getUnits() ~= nil and #_vhfGroup:getUnits() == 1 then - table.insert(_radioLoop, { group = _vhfGroup, freq = _beaconDetails.vhf, silent = false, mode = 0 }) - end - - if _uhfGroup ~= nil and _uhfGroup:getUnits() ~= nil and #_uhfGroup:getUnits() == 1 then - table.insert(_radioLoop, { group = _uhfGroup, freq = _beaconDetails.uhf, silent = true, mode = 0 }) - end - - if _fmGroup ~= nil and _fmGroup:getUnits() ~= nil and #_fmGroup:getUnits() == 1 then - table.insert(_radioLoop, { group = _fmGroup, freq = _beaconDetails.fm, silent = false, mode = 1 }) - end - - local _batLife = _beaconDetails.battery - timer.getTime() - - if (_batLife <= 0 and _beaconDetails.battery ~= -1) or #_radioLoop ~= 3 then - -- ran out of batteries - - if _vhfGroup ~= nil then - _vhfGroup:destroy() - end - if _uhfGroup ~= nil then - _uhfGroup:destroy() - end - if _fmGroup ~= nil then - _fmGroup:destroy() - end - - return false - end - - --fobs have unlimited battery life - -- if _battery ~= -1 then - -- _text = _text.." "..mist.utils.round(_batLife).." seconds of battery" - -- end - - for _, _radio in pairs(_radioLoop) do - - local _groupController = _radio.group:getController() - - local _sound = ctld.radioSound - if _radio.silent then - _sound = ctld.radioSoundFC3 - end - - _sound = "l10n/DEFAULT/".._sound - - _groupController:setOption(AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.WEAPON_HOLD) - - trigger.action.radioTransmission(_sound, _radio.group:getUnit(1):getPoint(), _radio.mode, false, _radio.freq, 1000) - --This function doesnt actually stop transmitting when then sound is false. My hope is it will stop if a new beacon is created on the same - -- frequency... OR they fix the bug where it wont stop. - -- end - - -- - end - - return true - - -- trigger.action.radioTransmission(ctld.radioSound, _point, 1, true, _frequency, 1000) -end - -function ctld.listRadioBeacons(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _message = "" - - if _heli ~= nil then - - for _x, _details in pairs(ctld.deployedRadioBeacons) do - - if _details.coalition == _heli:getCoalition() then - _message = _message .. _details.text .. "\n" - end - end - - if _message ~= "" then - ctld.displayMessageToGroup(_heli, "Radio Beacons:\n" .. _message, 20) - else - ctld.displayMessageToGroup(_heli, "No Active Radio Beacons", 20) - end - end -end - -function ctld.dropRadioBeacon(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _message = "" - - if _heli ~= nil and ctld.inAir(_heli) == false then - - --deploy 50 m infront - --try to spawn at 12 oclock to us - local _point = ctld.getPointAt12Oclock(_heli, 50) - - ctld.beaconCount = ctld.beaconCount + 1 - local _name = "Beacon #" .. ctld.beaconCount - - local _radioBeaconDetails = ctld.createRadioBeacon(_point, _heli:getCoalition(), _heli:getCountry(), _name, nil, false) - - -- mark with flare? - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " deployed a Radio Beacon.\n\n" .. _radioBeaconDetails.text, 20) - - else - ctld.displayMessageToGroup(_heli, "You need to land before you can deploy a Radio Beacon!", 20) - end -end - ---remove closet radio beacon -function ctld.removeRadioBeacon(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - local _message = "" - - if _heli ~= nil and ctld.inAir(_heli) == false then - - -- mark with flare? - - local _closetBeacon = nil - local _shortestDistance = -1 - local _distance = 0 - - for _x, _details in pairs(ctld.deployedRadioBeacons) do - - if _details.coalition == _heli:getCoalition() then - - local _group = Group.getByName(_details.vhfGroup) - - if _group ~= nil and #_group:getUnits() == 1 then - - _distance = ctld.getDistance(_heli:getPoint(), _group:getUnit(1):getPoint()) - if _distance ~= nil and (_shortestDistance == -1 or _distance < _shortestDistance) then - _shortestDistance = _distance - _closetBeacon = _details - end - end - end - end - - if _closetBeacon ~= nil and _shortestDistance then - local _vhfGroup = Group.getByName(_closetBeacon.vhfGroup) - - local _uhfGroup = Group.getByName(_closetBeacon.uhfGroup) - - local _fmGroup = Group.getByName(_closetBeacon.fmGroup) - - if _vhfGroup ~= nil then - _vhfGroup:destroy() - end - if _uhfGroup ~= nil then - _uhfGroup:destroy() - end - if _fmGroup ~= nil then - _fmGroup:destroy() - end - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " removed a Radio Beacon.\n\n" .. _closetBeacon.text, 20) - else - ctld.displayMessageToGroup(_heli, "No Radio Beacons within 500m.", 20) - end - - else - ctld.displayMessageToGroup(_heli, "You need to land before remove a Radio Beacon", 20) - end -end - --- gets the center of a bunch of points! --- return proper DCS point with height -function ctld.getCentroid(_points) - local _tx, _ty = 0, 0 - for _index, _point in ipairs(_points) do - _tx = _tx + _point.x - _ty = _ty + _point.z - end - - local _npoints = #_points - - local _point = { x = _tx / _npoints, z = _ty / _npoints } - - _point.y = land.getHeight({ _point.x, _point.z }) - - return _point -end - -function ctld.getAATemplate(_unitName) - - for _,_system in pairs(ctld.AASystemTemplate) do - - if _system.repair == _unitName then - return _system - end - - for _,_part in pairs(_system.parts) do - - if _unitName == _part.name then - return _system - end - end - end - - return nil - -end - -function ctld.getLauncherUnitFromAATemplate(_aaTemplate) - for _,_part in pairs(_aaTemplate.parts) do - - if _part.launcher then - return _part.name - end - end - - return nil -end - -function ctld.rearmAASystem(_heli, _nearestCrate, _nearbyCrates, _aaSystemTemplate) - - -- are we adding to existing aa system? - -- check to see if the crate is a launcher - if ctld.getLauncherUnitFromAATemplate(_aaSystemTemplate) == _nearestCrate.details.unit then - - -- find nearest COMPLETE AA system - local _nearestSystem = ctld.findNearestAASystem(_heli, _aaSystemTemplate) - - if _nearestSystem ~= nil and _nearestSystem.dist < 300 then - - local _uniqueTypes = {} -- stores each unique part of system - local _types = {} - local _points = {} - - local _units = _nearestSystem.group:getUnits() - - if _units ~= nil and #_units > 0 then - - for x = 1, #_units do - if _units[x]:getLife() > 0 then - - --this allows us to count each type once - _uniqueTypes[_units[x]:getTypeName()] = _units[x]:getTypeName() - - table.insert(_points, _units[x]:getPoint()) - table.insert(_types, _units[x]:getTypeName()) - end - end - end - - -- do we have the correct number of unique pieces and do we have enough points for all the pieces - if ctld.countTableEntries(_uniqueTypes) == _aaSystemTemplate.count and #_points >= _aaSystemTemplate.count then - - -- rearm aa system - -- destroy old group - ctld.completeAASystems[_nearestSystem.group:getName()] = nil - - _nearestSystem.group:destroy() - - local _spawnedGroup = ctld.spawnCrateGroup(_heli, _points, _types) - - ctld.completeAASystems[_spawnedGroup:getName()] = ctld.getAASystemDetails(_spawnedGroup, _aaSystemTemplate) - - ctld.processCallback({unit = _heli, crate = _nearestCrate , spawnedGroup = _spawnedGroup, action = "rearm"}) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully rearmed a full ".._aaSystemTemplate.name.." in the field", 10) - - if _heli:getCoalition() == 1 then - ctld.spawnedCratesRED[_nearestCrate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_nearestCrate.crateUnit:getName()] = nil - end - - -- remove crate - -- if ctld.slingLoad == false then - _nearestCrate.crateUnit:destroy() - -- end - - return true -- all done so quit - end - end - end - - return false -end - -function ctld.getAASystemDetails(_hawkGroup,_aaSystemTemplate) - - local _units = _hawkGroup:getUnits() - - local _hawkDetails = {} - - for _, _unit in pairs(_units) do - table.insert(_hawkDetails, { point = _unit:getPoint(), unit = _unit:getTypeName(), name = _unit:getName(), system =_aaSystemTemplate}) - end - - return _hawkDetails -end - -function ctld.countTableEntries(_table) - - if _table == nil then - return 0 - end - - - local _count = 0 - - for _key, _value in pairs(_table) do - - _count = _count + 1 - end - - return _count -end - -function ctld.unpackAASystem(_heli, _nearestCrate, _nearbyCrates,_aaSystemTemplate) - - if ctld.rearmAASystem(_heli, _nearestCrate, _nearbyCrates,_aaSystemTemplate) then - -- rearmed hawk - return - end - - -- are there all the pieces close enough together - local _systemParts = {} - - --initialise list of parts - for _,_part in pairs(_aaSystemTemplate.parts) do - _systemParts[_part.name] = {name = _part.name,desc = _part.desc,found = false} - end - - -- find all nearest crates and add them to the list if they're part of the AA System - for _, _nearbyCrate in pairs(_nearbyCrates) do - - if _nearbyCrate.dist < 500 then - - if _systemParts[_nearbyCrate.details.unit] ~= nil and _systemParts[_nearbyCrate.details.unit].found == false then - local _foundPart = _systemParts[_nearbyCrate.details.unit] - - _foundPart.found = true - _foundPart.crate = _nearbyCrate - - _systemParts[_nearbyCrate.details.unit] = _foundPart - end - end - end - - local _count = 0 - local _txt = "" - - local _posArray = {} - local _typeArray = {} - for _name, _systemPart in pairs(_systemParts) do - - if _systemPart.found == false then - _txt = _txt.."Missing ".._systemPart.desc.."\n" - else - - local _launcherPart = ctld.getLauncherUnitFromAATemplate(_aaSystemTemplate) - - --handle multiple launchers from one crate - if (_name == "Hawk ln" and ctld.hawkLaunchers > 1) - or (_launcherPart == _name and ctld.aaLaunchers > 1) then - - --add multiple launcher - local _launchers = ctld.aaLaunchers - - if _name == "Hawk ln" then - _launchers = ctld.hawkLaunchers - end - - for _i = 1, _launchers do - - -- spawn in a circle around the crate - local _angle = math.pi * 2 * (_i - 1) / _launchers - local _xOffset = math.cos(_angle) * 12 - local _yOffset = math.sin(_angle) * 12 - - local _point = _systemPart.crate.crateUnit:getPoint() - - _point = { x = _point.x + _xOffset, y = _point.y, z = _point.z + _yOffset } - - table.insert(_posArray, _point) - table.insert(_typeArray, _name) - end - else - table.insert(_posArray, _systemPart.crate.crateUnit:getPoint()) - table.insert(_typeArray, _name) - end - end - end - - local _activeLaunchers = ctld.countCompleteAASystems(_heli) - - local _allowed = ctld.getAllowedAASystems(_heli) - - env.info("Active: ".._activeLaunchers.." Allowed: ".._allowed) - - if _activeLaunchers + 1 > _allowed then - trigger.action.outTextForCoalition(_heli:getCoalition(), "Out of parts for AA Systems. Current limit is ".._allowed.." \n", 10) - return - end - - if _txt ~= "" then - ctld.displayMessageToGroup(_heli, "Cannot build ".._aaSystemTemplate.name.."\n" .. _txt .. "\n\nOr the crates are not close enough together", 20) - return - else - - -- destroy crates - for _name, _systemPart in pairs(_systemParts) do - - if _heli:getCoalition() == 1 then - ctld.spawnedCratesRED[_systemPart.crate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_systemPart.crate.crateUnit:getName()] = nil - end - - --destroy - -- if ctld.slingLoad == false then - _systemPart.crate.crateUnit:destroy() - --end - end - - -- HAWK / BUK READY! - local _spawnedGroup = ctld.spawnCrateGroup(_heli, _posArray, _typeArray) - - ctld.completeAASystems[_spawnedGroup:getName()] = ctld.getAASystemDetails(_spawnedGroup,_aaSystemTemplate) - - ctld.processCallback({unit = _heli, crate = _nearestCrate , spawnedGroup = _spawnedGroup, action = "unpack"}) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully deployed a full ".._aaSystemTemplate.name.." to the field. \n\nAA Active System limit is: ".._allowed.."\nActive: "..(_activeLaunchers+1), 10) - - end -end - ---count the number of captured cities, sets the amount of allowed AA Systems -function ctld.getAllowedAASystems(_heli) - - if _heli:getCoalition() == 1 then - return ctld.AASystemLimitBLUE - else - return ctld.AASystemLimitRED - end - - -end - - -function ctld.countCompleteAASystems(_heli) - - local _count = 0 - - for _groupName, _hawkDetails in pairs(ctld.completeAASystems) do - - local _hawkGroup = Group.getByName(_groupName) - - -- env.info(_groupName..": "..mist.utils.tableShow(_hawkDetails)) - if _hawkGroup ~= nil and _hawkGroup:getCoalition() == _heli:getCoalition() then - - local _units = _hawkGroup:getUnits() - - if _units ~=nil and #_units > 0 then - --get the system template - local _aaSystemTemplate = _hawkDetails[1].system - - local _uniqueTypes = {} -- stores each unique part of system - local _types = {} - local _points = {} - - if _units ~= nil and #_units > 0 then - - for x = 1, #_units do - if _units[x]:getLife() > 0 then - - --this allows us to count each type once - _uniqueTypes[_units[x]:getTypeName()] = _units[x]:getTypeName() - - table.insert(_points, _units[x]:getPoint()) - table.insert(_types, _units[x]:getTypeName()) - end - end - end - - -- do we have the correct number of unique pieces and do we have enough points for all the pieces - if ctld.countTableEntries(_uniqueTypes) == _aaSystemTemplate.count and #_points >= _aaSystemTemplate.count then - _count = _count +1 - end - end - end - end - - return _count -end - - -function ctld.repairAASystem(_heli, _nearestCrate,_aaSystem) - - -- find nearest COMPLETE AA system - local _nearestHawk = ctld.findNearestAASystem(_heli,_aaSystem) - - - - if _nearestHawk ~= nil and _nearestHawk.dist < 300 then - - local _oldHawk = ctld.completeAASystems[_nearestHawk.group:getName()] - - --spawn new one - - local _types = {} - local _points = {} - - for _, _part in pairs(_oldHawk) do - table.insert(_points, _part.point) - table.insert(_types, _part.unit) - end - - --remove old system - ctld.completeAASystems[_nearestHawk.group:getName()] = nil - _nearestHawk.group:destroy() - - local _spawnedGroup = ctld.spawnCrateGroup(_heli, _points, _types) - - ctld.completeAASystems[_spawnedGroup:getName()] = ctld.getAASystemDetails(_spawnedGroup,_aaSystem) - - ctld.processCallback({unit = _heli, crate = _nearestCrate , spawnedGroup = _spawnedGroup, action = "repair"}) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " successfully repaired a full ".._aaSystem.name.." in the field", 10) - - if _heli:getCoalition() == 1 then - ctld.spawnedCratesRED[_nearestCrate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_nearestCrate.crateUnit:getName()] = nil - end - - -- remove crate - -- if ctld.slingLoad == false then - _nearestCrate.crateUnit:destroy() - -- end - - else - ctld.displayMessageToGroup(_heli, "Cannot repair ".._aaSystem.name..". No damaged ".._aaSystem.name.." within 300m", 10) - end -end - -function ctld.unpackMultiCrate(_heli, _nearestCrate, _nearbyCrates) - - -- unpack multi crate - local _nearbyMultiCrates = {} - - for _, _nearbyCrate in pairs(_nearbyCrates) do - - if _nearbyCrate.dist < 300 then - - if _nearbyCrate.details.unit == _nearestCrate.details.unit then - - table.insert(_nearbyMultiCrates, _nearbyCrate) - - if #_nearbyMultiCrates == _nearestCrate.details.cratesRequired then - break - end - end - end - end - - --- check crate count - if #_nearbyMultiCrates == _nearestCrate.details.cratesRequired then - - local _point = _nearestCrate.crateUnit:getPoint() - - -- destroy crates - for _, _crate in pairs(_nearbyMultiCrates) do - - if _point == nil then - _point = _crate.crateUnit:getPoint() - end - - if _heli:getCoalition() == 1 then - ctld.spawnedCratesRED[_crate.crateUnit:getName()] = nil - else - ctld.spawnedCratesBLUE[_crate.crateUnit:getName()] = nil - end - - --destroy - -- if ctld.slingLoad == false then - _crate.crateUnit:destroy() - -- end - end - - - local _spawnedGroup = ctld.spawnCrateGroup(_heli, { _point }, { _nearestCrate.details.unit }) - - ctld.processCallback({unit = _heli, crate = _nearestCrate , spawnedGroup = _spawnedGroup, action = "unpack"}) - - local _txt = string.format("%s successfully deployed %s to the field using %d crates", ctld.getPlayerNameOrType(_heli), _nearestCrate.details.desc, #_nearbyMultiCrates) - - trigger.action.outTextForCoalition(_heli:getCoalition(), _txt, 10) - - else - - local _txt = string.format("Cannot build %s!\n\nIt requires %d crates and there are %d \n\nOr the crates are not within 300m of each other", _nearestCrate.details.desc, _nearestCrate.details.cratesRequired, #_nearbyMultiCrates) - - ctld.displayMessageToGroup(_heli, _txt, 20) - end -end - - -function ctld.spawnCrateGroup(_heli, _positions, _types) - - local _id = ctld.getNextGroupId() - - local _groupName = _types[1] .. " #" .. _id - - local _side = _heli:getCoalition() - - local _group = { - ["visible"] = false, - -- ["groupId"] = _id, - ["hidden"] = false, - ["units"] = {}, - -- ["y"] = _positions[1].z, - -- ["x"] = _positions[1].x, - ["name"] = _groupName, - ["task"] = {}, - } - - if #_positions == 1 then - - local _unitId = ctld.getNextUnitId() - local _details = { type = _types[1], unitId = _unitId, name = string.format("Unpacked %s #%i", _types[1], _unitId) } - - _group.units[1] = ctld.createUnit(_positions[1].x + 5, _positions[1].z + 5, 120, _details) - - else - - for _i, _pos in ipairs(_positions) do - - local _unitId = ctld.getNextUnitId() - local _details = { type = _types[_i], unitId = _unitId, name = string.format("Unpacked %s #%i", _types[_i], _unitId) } - - _group.units[_i] = ctld.createUnit(_pos.x + 5, _pos.z + 5, 120, _details) - end - end - - --mist function - _group.category = Group.Category.GROUND - _group.country = _heli:getCountry() - - local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) - - return _spawnedGroup -end - - - --- spawn normal group -function ctld.spawnDroppedGroup(_point, _details, _spawnBehind, _maxSearch) - - local _groupName = _details.groupName - - local _group = { - ["visible"] = false, - -- ["groupId"] = _details.groupId, - ["hidden"] = false, - ["units"] = {}, - -- ["y"] = _positions[1].z, - -- ["x"] = _positions[1].x, - ["name"] = _groupName, - ["task"] = {}, - } - - - if _spawnBehind == false then - - -- spawn in circle around heli - - local _pos = _point - - for _i, _detail in ipairs(_details.units) do - - local _angle = math.pi * 2 * (_i - 1) / #_details.units - local _xOffset = math.cos(_angle) * 30 - local _yOffset = math.sin(_angle) * 30 - - _group.units[_i] = ctld.createUnit(_pos.x + _xOffset, _pos.z + _yOffset, _angle, _detail) - end - - else - - local _pos = _point - - --try to spawn at 6 oclock to us - local _angle = math.atan2(_pos.z, _pos.x) - local _xOffset = math.cos(_angle) * -30 - local _yOffset = math.sin(_angle) * -30 - - - for _i, _detail in ipairs(_details.units) do - _group.units[_i] = ctld.createUnit(_pos.x + (_xOffset + 10 * _i), _pos.z + (_yOffset + 10 * _i), _angle, _detail) - end - end - - --switch to MIST - _group.category = Group.Category.GROUND; - _group.country = _details.country; - - local _spawnedGroup = Group.getByName(mist.dynAdd(_group).name) - - --local _spawnedGroup = coalition.addGroup(_details.country, Group.Category.GROUND, _group) - - - -- find nearest enemy and head there - if _maxSearch == nil then - _maxSearch = ctld.maximumSearchDistance - end - - local _wpZone = ctld.inWaypointZone(_point,_spawnedGroup:getCoalition()) - - if _wpZone.inZone then - ctld.orderGroupToMoveToPoint(_spawnedGroup:getUnit(1), _wpZone.point) - env.info("Heading to waypoint - In Zone ".._wpZone.name) - else - local _enemyPos = ctld.findNearestEnemy(_details.side, _point, _maxSearch) - - ctld.orderGroupToMoveToPoint(_spawnedGroup:getUnit(1), _enemyPos) - end - - return _spawnedGroup -end - -function ctld.findNearestEnemy(_side, _point, _searchDistance) - - local _closestEnemy = nil - - local _groups - - local _closestEnemyDist = _searchDistance - - local _heliPoint = _point - - if _side == 2 then - _groups = coalition.getGroups(1, Group.Category.GROUND) - else - _groups = coalition.getGroups(2, Group.Category.GROUND) - end - - for _, _group in pairs(_groups) do - - if _group ~= nil then - local _units = _group:getUnits() - - if _units ~= nil and #_units > 0 then - - local _leader = nil - - -- find alive leader - for x = 1, #_units do - if _units[x]:getLife() > 0 then - _leader = _units[x] - break - end - end - - if _leader ~= nil then - local _leaderPos = _leader:getPoint() - local _dist = ctld.getDistance(_heliPoint, _leaderPos) - if _dist < _closestEnemyDist then - _closestEnemyDist = _dist - _closestEnemy = _leaderPos - end - end - end - end - end - - - -- no enemy - move to random point - if _closestEnemy ~= nil then - - -- env.info("found enemy") - return _closestEnemy - else - - local _x = _heliPoint.x + math.random(0, ctld.maximumMoveDistance) - math.random(0, ctld.maximumMoveDistance) - local _z = _heliPoint.z + math.random(0, ctld.maximumMoveDistance) - math.random(0, ctld.maximumMoveDistance) - local _y = _heliPoint.y + math.random(0, ctld.maximumMoveDistance) - math.random(0, ctld.maximumMoveDistance) - - return { x = _x, z = _z,y=_y } - end -end - -function ctld.findNearestGroup(_heli, _groups) - - local _closestGroupDetails = {} - local _closestGroup = nil - - local _closestGroupDist = ctld.maxExtractDistance - - local _heliPoint = _heli:getPoint() - - for _, _groupName in pairs(_groups) do - - local _group = Group.getByName(_groupName) - - if _group ~= nil then - local _units = _group:getUnits() - - if _units ~= nil and #_units > 0 then - - local _leader = nil - - local _groupDetails = { groupId = _group:getID(), groupName = _group:getName(), side = _group:getCoalition(), units = {} } - - -- find alive leader - for x = 1, #_units do - if _units[x]:getLife() > 0 then - - if _leader == nil then - _leader = _units[x] - -- set country based on leader - _groupDetails.country = _leader:getCountry() - end - - local _unitDetails = { type = _units[x]:getTypeName(), unitId = _units[x]:getID(), name = _units[x]:getName() } - - table.insert(_groupDetails.units, _unitDetails) - end - end - - if _leader ~= nil then - local _leaderPos = _leader:getPoint() - local _dist = ctld.getDistance(_heliPoint, _leaderPos) - if _dist < _closestGroupDist then - _closestGroupDist = _dist - _closestGroupDetails = _groupDetails - _closestGroup = _group - end - end - end - end - end - - - if _closestGroup ~= nil then - - return { group = _closestGroup, details = _closestGroupDetails } - else - - return nil - end -end - - -function ctld.createUnit(_x, _y, _angle, _details) - - local _newUnit = { - ["y"] = _y, - ["type"] = _details.type, - ["name"] = _details.name, - -- ["unitId"] = _details.unitId, - ["heading"] = _angle, - ["playerCanDrive"] = true, - ["skill"] = "Excellent", - ["x"] = _x, - } - - return _newUnit -end - -function ctld.addEWRTask(_group) - - -- delayed 2 second to work around bug - timer.scheduleFunction(function(_ewrGroup) - local _grp = ctld.getAliveGroup(_ewrGroup) - - if _grp ~= nil then - local _controller = _grp:getController(); - local _EWR = { - id = 'EWR', - auto = true, - params = { - } - } - _controller:setTask(_EWR) - end - end - , _group:getName(), timer.getTime() + 2) - -end - -function ctld.orderGroupToMoveToPoint(_leader, _destination) - - local _group = _leader:getGroup() - - local _path = {} - table.insert(_path, mist.ground.buildWP(_leader:getPoint(), 'Off Road', 50)) - table.insert(_path, mist.ground.buildWP(_destination, 'Off Road', 50)) - - local _mission = { - id = 'Mission', - params = { - route = { - points =_path - }, - }, - } - - - -- delayed 2 second to work around bug - timer.scheduleFunction(function(_arg) - local _grp = ctld.getAliveGroup(_arg[1]) - - if _grp ~= nil then - local _controller = _grp:getController(); - Controller.setOption(_controller, AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.AUTO) - Controller.setOption(_controller, AI.Option.Ground.id.ROE, AI.Option.Ground.val.ROE.OPEN_FIRE) - _controller:setTask(_arg[2]) - end - end - , {_group:getName(), _mission}, timer.getTime() + 2) - -end - --- are we in pickup zone -function ctld.inPickupZone(_heli) - ctld.logDebug(string.format("ctld.inPickupZone(_heli=%s)", ctld.p(_heli))) - - if ctld.inAir(_heli) then - return { inZone = false, limit = -1, index = -1 } - end - - local _heliPoint = _heli:getPoint() - - for _i, _zoneDetails in pairs(ctld.pickupZones) do - ctld.logTrace(string.format("_zoneDetails=%s", ctld.p(_zoneDetails))) - - local _triggerZone = trigger.misc.getZone(_zoneDetails[1]) - - if _triggerZone == nil then - local _ship = ctld.getTransportUnit(_zoneDetails[1]) - - if _ship then - local _point = _ship:getPoint() - _triggerZone = {} - _triggerZone.point = _point - _triggerZone.radius = 200 -- should be big enough for ship - end - - end - - if _triggerZone ~= nil then - - --get distance to center - - local _dist = ctld.getDistance(_heliPoint, _triggerZone.point) - ctld.logTrace(string.format("_dist=%s", ctld.p(_dist))) - if _dist <= _triggerZone.radius then - local _heliCoalition = _heli:getCoalition() - if _zoneDetails[4] == 1 and (_zoneDetails[5] == _heliCoalition or _zoneDetails[5] == 0) then - return { inZone = true, limit = _zoneDetails[3], index = _i } - end - end - end - end - - local _fobs = ctld.getSpawnedFobs(_heli) - - -- now check spawned fobs - for _, _fob in ipairs(_fobs) do - - --get distance to center - - local _dist = ctld.getDistance(_heliPoint, _fob:getPoint()) - - if _dist <= 150 then - return { inZone = true, limit = 10000, index = -1 }; - end - end - - - - return { inZone = false, limit = -1, index = -1 }; -end - -function ctld.getSpawnedFobs(_heli) - - local _fobs = {} - - for _, _fobName in ipairs(ctld.builtFOBS) do - - local _fob = StaticObject.getByName(_fobName) - - if _fob ~= nil and _fob:isExist() and _fob:getCoalition() == _heli:getCoalition() and _fob:getLife() > 0 then - - table.insert(_fobs, _fob) - end - end - - return _fobs -end - --- are we in a dropoff zone -function ctld.inDropoffZone(_heli) - - if ctld.inAir(_heli) then - return false - end - - local _heliPoint = _heli:getPoint() - - for _, _zoneDetails in pairs(ctld.dropOffZones) do - - local _triggerZone = trigger.misc.getZone(_zoneDetails[1]) - - if _triggerZone ~= nil and (_zoneDetails[3] == _heli:getCoalition() or _zoneDetails[3]== 0) then - - --get distance to center - - local _dist = ctld.getDistance(_heliPoint, _triggerZone.point) - - if _dist <= _triggerZone.radius then - return true - end - end - end - - return false -end - --- are we in a waypoint zone -function ctld.inWaypointZone(_point,_coalition) - - for _, _zoneDetails in pairs(ctld.wpZones) do - - local _triggerZone = trigger.misc.getZone(_zoneDetails[1]) - - --right coalition and active? - if _triggerZone ~= nil and (_zoneDetails[4] == _coalition or _zoneDetails[4]== 0) and _zoneDetails[3] == 1 then - - --get distance to center - - local _dist = ctld.getDistance(_point, _triggerZone.point) - - if _dist <= _triggerZone.radius then - return {inZone = true, point = _triggerZone.point, name = _zoneDetails[1]} - end - end - end - - return {inZone = false} -end - --- are we near friendly logistics zone -function ctld.inLogisticsZone(_heli) - - if ctld.inAir(_heli) then - return false - end - - local _heliPoint = _heli:getPoint() - - for _, _name in pairs(ctld.logisticUnits) do - - local _logistic = StaticObject.getByName(_name) - - if _logistic ~= nil and _logistic:getCoalition() == _heli:getCoalition() then - - --get distance - local _dist = ctld.getDistance(_heliPoint, _logistic:getPoint()) - - if _dist <= ctld.maximumDistanceLogistic then - return true - end - end - end - - return false -end - - --- are far enough from a friendly logistics zone -function ctld.farEnoughFromLogisticZone(_heli) - - if ctld.inAir(_heli) then - return false - end - - local _heliPoint = _heli:getPoint() - - local _farEnough = true - - for _, _name in pairs(ctld.logisticUnits) do - - local _logistic = StaticObject.getByName(_name) - - if _logistic ~= nil and _logistic:getCoalition() == _heli:getCoalition() then - - --get distance - local _dist = ctld.getDistance(_heliPoint, _logistic:getPoint()) - -- env.info("DIST ".._dist) - if _dist <= ctld.minimumDeployDistance then - -- env.info("TOO CLOSE ".._dist) - _farEnough = false - end - end - end - - return _farEnough -end - -function ctld.refreshSmoke() - - if ctld.disableAllSmoke == true then - return - end - - for _, _zoneGroup in pairs({ ctld.pickupZones, ctld.dropOffZones }) do - - for _, _zoneDetails in pairs(_zoneGroup) do - - local _triggerZone = trigger.misc.getZone(_zoneDetails[1]) - - if _triggerZone == nil then - local _ship = ctld.getTransportUnit(_triggerZone) - - if _ship then - local _point = _ship:getPoint() - _triggerZone = {} - _triggerZone.point = _point - end - - end - - - --only trigger if smoke is on AND zone is active - if _triggerZone ~= nil and _zoneDetails[2] >= 0 and _zoneDetails[4] == 1 then - - -- Trigger smoke markers - - local _pos2 = { x = _triggerZone.point.x, y = _triggerZone.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - trigger.action.smoke(_pos3, _zoneDetails[2]) - end - end - end - - --waypoint zones - for _, _zoneDetails in pairs(ctld.wpZones) do - - local _triggerZone = trigger.misc.getZone(_zoneDetails[1]) - - --only trigger if smoke is on AND zone is active - if _triggerZone ~= nil and _zoneDetails[2] >= 0 and _zoneDetails[3] == 1 then - - -- Trigger smoke markers - - local _pos2 = { x = _triggerZone.point.x, y = _triggerZone.point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y } - - trigger.action.smoke(_pos3, _zoneDetails[2]) - end - end - - - --refresh in 5 minutes - timer.scheduleFunction(ctld.refreshSmoke, nil, timer.getTime() + 300) -end - -function ctld.dropSmoke(_args) - - local _heli = ctld.getTransportUnit(_args[1]) - - if _heli ~= nil then - - local _colour = "" - - if _args[2] == trigger.smokeColor.Red then - - _colour = "RED" - elseif _args[2] == trigger.smokeColor.Blue then - - _colour = "BLUE" - elseif _args[2] == trigger.smokeColor.Green then - - _colour = "GREEN" - elseif _args[2] == trigger.smokeColor.Orange then - - _colour = "ORANGE" - end - - local _point = _heli:getPoint() - - local _pos2 = { x = _point.x, y = _point.z } - local _alt = land.getHeight(_pos2) - local _pos3 = { x = _point.x, y = _alt, z = _point.z } - - trigger.action.smoke(_pos3, _args[2]) - - trigger.action.outTextForCoalition(_heli:getCoalition(), ctld.getPlayerNameOrType(_heli) .. " dropped " .. _colour .. " smoke ", 10) - end -end - -function ctld.unitCanCarryVehicles(_unit) - - local _type = string.lower(_unit:getTypeName()) - - for _, _name in ipairs(ctld.vehicleTransportEnabled) do - local _nameLower = string.lower(_name) - if string.match(_type, _nameLower) then - return true - end - end - - return false -end - -function ctld.isJTACUnitType(_type) - - _type = string.lower(_type) - - for _, _name in ipairs(ctld.jtacUnitTypes) do - local _nameLower = string.lower(_name) - if string.match(_type, _nameLower) then - return true - end - end - - return false -end - -function ctld.updateZoneCounter(_index, _diff) - - if ctld.pickupZones[_index] ~= nil then - - ctld.pickupZones[_index][3] = ctld.pickupZones[_index][3] + _diff - - if ctld.pickupZones[_index][3] < 0 then - ctld.pickupZones[_index][3] = 0 - end - - if ctld.pickupZones[_index][6] ~= nil then - trigger.action.setUserFlag(ctld.pickupZones[_index][6], ctld.pickupZones[_index][3]) - end - -- env.info(ctld.pickupZones[_index][1].." = " ..ctld.pickupZones[_index][3]) - end -end - -function ctld.processCallback(_callbackArgs) - - for _, _callback in pairs(ctld.callbacks) do - - local _status, _result = pcall(function() - - _callback(_callbackArgs) - - end) - - if (not _status) then - env.error(string.format("CTLD Callback Error: %s", _result)) - end - end -end - - --- checks the status of all AI troop carriers and auto loads and unloads troops --- as long as the troops are on the ground -function ctld.checkAIStatus() - - timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 2) - - - for _, _unitName in pairs(ctld.transportPilotNames) do - local status, error = pcall(function() - - local _unit = ctld.getTransportUnit(_unitName) - - -- no player name means AI! - if _unit ~= nil and _unit:getPlayerName() == nil then - local _zone = ctld.inPickupZone(_unit) - -- env.error("Checking.. ".._unit:getName()) - if _zone.inZone == true and not ctld.troopsOnboard(_unit, true) then - -- env.error("in zone, loading.. ".._unit:getName()) - - if ctld.allowRandomAiTeamPickups == true then - -- Random troop pickup implementation - local _team = nil - if _unit:getCoalition() == 1 then - _team = math.floor((math.random(#ctld.redTeams * 100) / 100) + 1) - ctld.loadTroopsFromZone({ _unitName, true,ctld.loadableGroups[ctld.redTeams[_team]],true }) - else - _team = math.floor((math.random(#ctld.blueTeams * 100) / 100) + 1) - ctld.loadTroopsFromZone({ _unitName, true,ctld.loadableGroups[ctld.blueTeams[_team]],true }) - end - else - ctld.loadTroopsFromZone({ _unitName, true,"",true }) - end - - elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, true) then - -- env.error("in dropoff zone, unloading.. ".._unit:getName()) - ctld.unloadTroops( { _unitName, true }) - end - - if ctld.unitCanCarryVehicles(_unit) then - - if _zone.inZone == true and not ctld.troopsOnboard(_unit, false) then - - ctld.loadTroopsFromZone({ _unitName, false,"",true }) - - elseif ctld.inDropoffZone(_unit) and ctld.troopsOnboard(_unit, false) then - - ctld.unloadTroops( { _unitName, false }) - end - end - end - end) - - if (not status) then - env.error(string.format("Error with ai status: %s", error), false) - end - end - - -end - -function ctld.getTransportLimit(_unitType) - - if ctld.unitLoadLimits[_unitType] then - - return ctld.unitLoadLimits[_unitType] - end - - return ctld.numberOfTroops - -end - -function ctld.getUnitActions(_unitType) - - if ctld.unitActions[_unitType] then - return ctld.unitActions[_unitType] - end - - return {crates=true,troops=true} - -end - --- Adds menuitem to all heli units that are active -function ctld.addF10MenuOptions() - -- Loop through all Heli units - - timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 10) - - for _, _unitName in pairs(ctld.transportPilotNames) do - - local status, error = pcall(function() - - local _unit = ctld.getTransportUnit(_unitName) - - if _unit ~= nil then - - local _groupId = ctld.getGroupId(_unit) - - if _groupId then - - if ctld.addedTo[tostring(_groupId)] == nil then - - local _rootPath = missionCommands.addSubMenuForGroup(_groupId, "CTLD") - - local _unitActions = ctld.getUnitActions(_unit:getTypeName()) - ctld.logTrace(string.format("_unitActions=%s", ctld.p(_unitActions))) - - missionCommands.addCommandForGroup(_groupId, "Check Cargo", _rootPath, ctld.checkTroopStatus, { _unitName }) - - if _unitActions.troops then - - local _troopCommandsPath = missionCommands.addSubMenuForGroup(_groupId, "Troop Transport", _rootPath) - - missionCommands.addCommandForGroup(_groupId, "Unload / Extract Troops", _troopCommandsPath, ctld.unloadExtractTroops, { _unitName }) - - - -- local _loadPath = missionCommands.addSubMenuForGroup(_groupId, "Load From Zone", _troopCommandsPath) - local _transportLimit = ctld.getTransportLimit(_unit:getTypeName()) - ctld.logTrace(string.format("_transportLimit=%s", ctld.p(_transportLimit))) - for _,_loadGroup in pairs(ctld.loadableGroups) do - ctld.logTrace(string.format("_loadGroup=%s", ctld.p(_loadGroup))) - if not _loadGroup.side or _loadGroup.side == _unit:getCoalition() then - - -- check size & unit - if _transportLimit >= _loadGroup.total then - missionCommands.addCommandForGroup(_groupId, "Load ".._loadGroup.name, _troopCommandsPath, ctld.loadTroopsFromZone, { _unitName, true,_loadGroup,false }) - end - end - end - - if ctld.unitCanCarryVehicles(_unit) then - - local _vehicleCommandsPath = missionCommands.addSubMenuForGroup(_groupId, "Vehicle / FOB Transport", _rootPath) - - missionCommands.addCommandForGroup(_groupId, "Unload Vehicles", _vehicleCommandsPath, ctld.unloadTroops, { _unitName, false }) - missionCommands.addCommandForGroup(_groupId, "Load / Extract Vehicles", _vehicleCommandsPath, ctld.loadTroopsFromZone, { _unitName, false,"",true }) - - if ctld.enabledFOBBuilding and ctld.staticBugWorkaround == false then - - missionCommands.addCommandForGroup(_groupId, "Load / Unload FOB Crate", _vehicleCommandsPath, ctld.loadUnloadFOBCrate, { _unitName, false }) - end - missionCommands.addCommandForGroup(_groupId, "Check Cargo", _vehicleCommandsPath, ctld.checkTroopStatus, { _unitName }) - end - - end - - - if ctld.enableCrates and _unitActions.crates then - - if ctld.unitCanCarryVehicles(_unit) == false then - - -- local _cratePath = missionCommands.addSubMenuForGroup(_groupId, "Spawn Crate", _rootPath) - -- add menu for spawning crates - for _subMenuName, _crates in pairs(ctld.spawnableCrates) do - - local _cratePath = missionCommands.addSubMenuForGroup(_groupId, _subMenuName, _rootPath) - for _, _crate in pairs(_crates) do - - if ctld.isJTACUnitType(_crate.unit) == false - or (ctld.isJTACUnitType(_crate.unit) == true and ctld.JTAC_dropEnabled) then - if _crate.side == nil or (_crate.side == _unit:getCoalition()) then - - local _crateRadioMsg = _crate.desc - - --add in the number of crates required to build something - if _crate.cratesRequired ~= nil and _crate.cratesRequired > 1 then - _crateRadioMsg = _crateRadioMsg.." (".._crate.cratesRequired..")" - end - - missionCommands.addCommandForGroup(_groupId,_crateRadioMsg, _cratePath, ctld.spawnCrate, { _unitName, _crate.weight }) - end - end - end - end - end - end - - if (ctld.enabledFOBBuilding or ctld.enableCrates) and _unitActions.crates then - - local _crateCommands = missionCommands.addSubMenuForGroup(_groupId, "CTLD Commands", _rootPath) - if ctld.hoverPickup == false then - if ctld.slingLoad == false then - missionCommands.addCommandForGroup(_groupId, "Load Nearby Crate", _crateCommands, ctld.loadNearbyCrate, _unitName ) - end - end - - missionCommands.addCommandForGroup(_groupId, "Unpack Any Crate", _crateCommands, ctld.unpackCrates, { _unitName }) - - if ctld.slingLoad == false then - missionCommands.addCommandForGroup(_groupId, "Drop Crate", _crateCommands, ctld.dropSlingCrate, { _unitName }) - end - - missionCommands.addCommandForGroup(_groupId, "List Nearby Crates", _crateCommands, ctld.listNearbyCrates, { _unitName }) - - if ctld.enabledFOBBuilding then - missionCommands.addCommandForGroup(_groupId, "List FOBs", _crateCommands, ctld.listFOBS, { _unitName }) - end - end - - - if ctld.enableSmokeDrop then - local _smokeMenu = missionCommands.addSubMenuForGroup(_groupId, "Smoke Markers", _rootPath) - missionCommands.addCommandForGroup(_groupId, "Drop Red Smoke", _smokeMenu, ctld.dropSmoke, { _unitName, trigger.smokeColor.Red }) - missionCommands.addCommandForGroup(_groupId, "Drop Blue Smoke", _smokeMenu, ctld.dropSmoke, { _unitName, trigger.smokeColor.Blue }) - missionCommands.addCommandForGroup(_groupId, "Drop Orange Smoke", _smokeMenu, ctld.dropSmoke, { _unitName, trigger.smokeColor.Orange }) - missionCommands.addCommandForGroup(_groupId, "Drop Green Smoke", _smokeMenu, ctld.dropSmoke, { _unitName, trigger.smokeColor.Green }) - end - - if ctld.enabledRadioBeaconDrop then - local _radioCommands = missionCommands.addSubMenuForGroup(_groupId, "Radio Beacons", _rootPath) - missionCommands.addCommandForGroup(_groupId, "List Beacons", _radioCommands, ctld.listRadioBeacons, { _unitName }) - missionCommands.addCommandForGroup(_groupId, "Drop Beacon", _radioCommands, ctld.dropRadioBeacon, { _unitName }) - missionCommands.addCommandForGroup(_groupId, "Remove Closet Beacon", _radioCommands, ctld.removeRadioBeacon, { _unitName }) - elseif ctld.deployedRadioBeacons ~= {} then - local _radioCommands = missionCommands.addSubMenuForGroup(_groupId, "Radio Beacons", _rootPath) - missionCommands.addCommandForGroup(_groupId, "List Beacons", _radioCommands, ctld.listRadioBeacons, { _unitName }) - end - - ctld.addedTo[tostring(_groupId)] = true - end - end - else - -- env.info(string.format("unit nil %s",_unitName)) - end - end) - - if (not status) then - env.error(string.format("Error adding f10 to transport: %s", error), false) - end - end - - local status, error = pcall(function() - - -- now do any player controlled aircraft that ARENT transport units - if ctld.enabledRadioBeaconDrop then - -- get all BLUE players - ctld.addRadioListCommand(2) - - -- get all RED players - ctld.addRadioListCommand(1) - end - - - if ctld.JTAC_jtacStatusF10 then - -- get all BLUE players - ctld.addJTACRadioCommand(2) - - -- get all RED players - ctld.addJTACRadioCommand(1) - end - - end) - - if (not status) then - env.error(string.format("Error adding f10 to other players: %s", error), false) - end - - -end - ---add to all players that arent transport -function ctld.addRadioListCommand(_side) - - local _players = coalition.getPlayers(_side) - - if _players ~= nil then - - for _, _playerUnit in pairs(_players) do - - local _groupId = ctld.getGroupId(_playerUnit) - - if _groupId then - - if ctld.addedTo[tostring(_groupId)] == nil then - missionCommands.addCommandForGroup(_groupId, "List Radio Beacons", nil, ctld.listRadioBeacons, { _playerUnit:getName() }) - ctld.addedTo[tostring(_groupId)] = true - end - end - end - end -end - -function ctld.addJTACRadioCommand(_side) - - local _players = coalition.getPlayers(_side) - - if _players ~= nil then - - for _, _playerUnit in pairs(_players) do - - local _groupId = ctld.getGroupId(_playerUnit) - - if _groupId then - -- env.info("adding command for "..index) - if ctld.jtacRadioAdded[tostring(_groupId)] == nil then - -- env.info("about command for "..index) - missionCommands.addCommandForGroup(_groupId, "JTAC Status", nil, ctld.getJTACStatus, { _playerUnit:getName() }) - ctld.jtacRadioAdded[tostring(_groupId)] = true - -- env.info("Added command for " .. index) - end - end - - - end - end -end - -function ctld.getGroupId(_unit) - - local _unitDB = mist.DBs.unitsById[tonumber(_unit:getID())] - if _unitDB ~= nil and _unitDB.groupId then - return _unitDB.groupId - end - - return nil -end - ---get distance in meters assuming a Flat world -function ctld.getDistance(_point1, _point2) - - local xUnit = _point1.x - local yUnit = _point1.z - local xZone = _point2.x - local yZone = _point2.z - - local xDiff = xUnit - xZone - local yDiff = yUnit - yZone - - return math.sqrt(xDiff * xDiff + yDiff * yDiff) -end - - ------------- JTAC ----------- - - -ctld.jtacLaserPoints = {} -ctld.jtacIRPoints = {} -ctld.jtacSmokeMarks = {} -ctld.jtacUnits = {} -- list of JTAC units for f10 command -ctld.jtacStop = {} -- jtacs to tell to stop lasing -ctld.jtacCurrentTargets = {} -ctld.jtacRadioAdded = {} --keeps track of who's had the radio command added -ctld.jtacGeneratedLaserCodes = {} -- keeps track of generated codes, cycles when they run out -ctld.jtacLaserPointCodes = {} -ctld.jtacRadioData = {} - -function ctld.JTACAutoLase(_jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio) - ctld.logDebug(string.format("ctld.JTACAutoLase(_jtacGroupName=%s, _laserCode=%s", ctld.p(_jtacGroupName), ctld.p(_laserCode))) - - local _radio = _radio - if not _radio then - _radio = {} - if _laserCode then - local _laserCode = tonumber(_laserCode) - if _laserCode and _laserCode >= 1111 and _laserCode <= 1688 then - local _laserB = math.floor((_laserCode - 1000)/100) - local _laserCD = _laserCode - 1000 - _laserB*100 - local _frequency = tostring(30+_laserB+_laserCD*0.05) - ctld.logTrace(string.format("_laserB=%s", ctld.p(_laserB))) - ctld.logTrace(string.format("_laserCD=%s", ctld.p(_laserCD))) - ctld.logTrace(string.format("_frequency=%s", ctld.p(_frequency))) - _radio.freq = _frequency - _radio.mod = "fm" - end - end - end - - if _radio and not _radio.name then - _radio.name = _jtacGroupName - end - - if ctld.jtacStop[_jtacGroupName] == true then - ctld.jtacStop[_jtacGroupName] = nil -- allow it to be started again - ctld.cleanupJTAC(_jtacGroupName) - return - end - - if _lock == nil then - - _lock = ctld.JTAC_lock - end - - - ctld.jtacLaserPointCodes[_jtacGroupName] = _laserCode - ctld.jtacRadioData[_jtacGroupName] = _radio - - local _jtacGroup = ctld.getGroup(_jtacGroupName) - local _jtacUnit - - if _jtacGroup == nil or #_jtacGroup == 0 then - - --check not in a heli - if ctld.inTransitTroops then - for _, _onboard in pairs(ctld.inTransitTroops) do - if _onboard ~= nil then - if _onboard.troops ~= nil and _onboard.troops.groupName ~= nil and _onboard.troops.groupName == _jtacGroupName then - - --jtac soldier being transported by heli - ctld.cleanupJTAC(_jtacGroupName) - - env.info(_jtacGroupName .. ' in Transport - Waiting 10 seconds') - timer.scheduleFunction(ctld.timerJTACAutoLase, { _jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio }, timer.getTime() + 10) - return - end - - if _onboard.vehicles ~= nil and _onboard.vehicles.groupName ~= nil and _onboard.vehicles.groupName == _jtacGroupName then - --jtac vehicle being transported by heli - ctld.cleanupJTAC(_jtacGroupName) - - env.info(_jtacGroupName .. ' in Transport - Waiting 10 seconds') - timer.scheduleFunction(ctld.timerJTACAutoLase, { _jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio }, timer.getTime() + 10) - return - end - end - end - end - - - if ctld.jtacUnits[_jtacGroupName] ~= nil then - ctld.notifyCoalition("JTAC Group " .. _jtacGroupName .. " KIA!", 10, ctld.jtacUnits[_jtacGroupName].side, _radio) - end - - --remove from list - ctld.jtacUnits[_jtacGroupName] = nil - - ctld.cleanupJTAC(_jtacGroupName) - - return - else - - _jtacUnit = _jtacGroup[1] - --add to list - ctld.jtacUnits[_jtacGroupName] = { name = _jtacUnit:getName(), side = _jtacUnit:getCoalition(), radio = _radio } - - -- work out smoke colour - if _colour == nil then - - if _jtacUnit:getCoalition() == 1 then - _colour = ctld.JTAC_smokeColour_RED - else - _colour = ctld.JTAC_smokeColour_BLUE - end - end - - - if _smoke == nil then - - if _jtacUnit:getCoalition() == 1 then - _smoke = ctld.JTAC_smokeOn_RED - else - _smoke = ctld.JTAC_smokeOn_BLUE - end - end - end - - - -- search for current unit - - if _jtacUnit:isActive() == false then - - ctld.cleanupJTAC(_jtacGroupName) - - env.info(_jtacGroupName .. ' Not Active - Waiting 30 seconds') - timer.scheduleFunction(ctld.timerJTACAutoLase, { _jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio }, timer.getTime() + 30) - - return - end - - local _enemyUnit = ctld.getCurrentUnit(_jtacUnit, _jtacGroupName) - local targetDestroyed = false - local targetLost = false - - if _enemyUnit == nil and ctld.jtacCurrentTargets[_jtacGroupName] ~= nil then - - local _tempUnitInfo = ctld.jtacCurrentTargets[_jtacGroupName] - - -- env.info("TEMP UNIT INFO: " .. tempUnitInfo.name .. " " .. tempUnitInfo.unitType) - - local _tempUnit = Unit.getByName(_tempUnitInfo.name) - - if _tempUnit ~= nil and _tempUnit:getLife() > 0 and _tempUnit:isActive() == true then - targetLost = true - else - targetDestroyed = true - end - - --remove from smoke list - ctld.jtacSmokeMarks[_tempUnitInfo.name] = nil - - -- JTAC Unit: resume his route ------------ - trigger.action.groupContinueMoving(Group.getByName(_jtacGroupName)) - - -- remove from target list - ctld.jtacCurrentTargets[_jtacGroupName] = nil - - --stop lasing - ctld.cancelLase(_jtacGroupName) - end - - - if _enemyUnit == nil then - _enemyUnit = ctld.findNearestVisibleEnemy(_jtacUnit, _lock) - - if _enemyUnit ~= nil then - - -- store current target for easy lookup - ctld.jtacCurrentTargets[_jtacGroupName] = { name = _enemyUnit:getName(), unitType = _enemyUnit:getTypeName(), unitId = _enemyUnit:getID() } - local action = ", lasing new target, " - if targetLost then - action = ", target lost " .. action - targetLost = false - elseif targetDestroyed then - action = ", target destroyed " .. action - targetDestroyed = false - end - - local message = _jtacGroupName .. action .. _enemyUnit:getTypeName() - local fullMessage = message .. '. CODE: ' .. _laserCode .. ". POSITION: " .. ctld.getPositionString(_enemyUnit) - ctld.notifyCoalition(fullMessage, 10, _jtacUnit:getCoalition(), _radio, message) - - -- JTAC Unit stop his route ----------------- - trigger.action.groupStopMoving(Group.getByName(_jtacGroupName)) -- stop JTAC - - -- create smoke - if _smoke == true then - - --create first smoke - ctld.createSmokeMarker(_enemyUnit, _colour) - end - end - end - - if _enemyUnit ~= nil then - - ctld.laseUnit(_enemyUnit, _jtacUnit, _jtacGroupName, _laserCode) - - -- env.info('Timer timerSparkleLase '..jtacGroupName.." "..laserCode.." "..enemyUnit:getName()) - timer.scheduleFunction(ctld.timerJTACAutoLase, { _jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio }, timer.getTime() + 15) - - - if _smoke == true then - local _nextSmokeTime = ctld.jtacSmokeMarks[_enemyUnit:getName()] - - --recreate smoke marker after 5 mins - if _nextSmokeTime ~= nil and _nextSmokeTime < timer.getTime() then - - ctld.createSmokeMarker(_enemyUnit, _colour) - end - end - - else - -- env.info('LASE: No Enemies Nearby') - - -- stop lazing the old spot - ctld.cancelLase(_jtacGroupName) - -- env.info('Timer Slow timerSparkleLase '..jtacGroupName.." "..laserCode.." "..enemyUnit:getName()) - - timer.scheduleFunction(ctld.timerJTACAutoLase, { _jtacGroupName, _laserCode, _smoke, _lock, _colour, _radio }, timer.getTime() + 5) - end - - if targetLost then - ctld.notifyCoalition(_jtacGroupName .. ", target lost.", 10, _jtacUnit:getCoalition(), _radio) - elseif targetDestroyed then - ctld.notifyCoalition(_jtacGroupName .. ", target destroyed.", 10, _jtacUnit:getCoalition(), _radio) - end -end - -function ctld.JTACAutoLaseStop(_jtacGroupName) - ctld.jtacStop[_jtacGroupName] = true -end - --- used by the timer function -function ctld.timerJTACAutoLase(_args) - - ctld.JTACAutoLase(_args[1], _args[2], _args[3], _args[4], _args[5], _args[6]) -end - -function ctld.cleanupJTAC(_jtacGroupName) - -- clear laser - just in case - ctld.cancelLase(_jtacGroupName) - - -- Cleanup - ctld.jtacUnits[_jtacGroupName] = nil - - ctld.jtacCurrentTargets[_jtacGroupName] = nil - - ctld.jtacRadioData[_jtacGroupName] = nil -end - - ---- send a message to the coalition ---- if _radio is set, the message will be read out loud via SRS -function ctld.notifyCoalition(_message, _displayFor, _side, _radio, _shortMessage) - ctld.logDebug(string.format("ctld.notifyCoalition(_message=%s)", ctld.p(_message))) - ctld.logTrace(string.format("_radio=%s", ctld.p(_radio))) - - local _shortMessage = _shortMessage - if _shortMessage == nil then - _shortMessage = _message - end - - if STTS and STTS.TextToSpeech and _radio and _radio.freq then - local _freq = _radio.freq - local _modulation = _radio.mod or "FM" - local _volume = _radio.volume or "1.0" - local _name = _radio.name or "JTAC" - local _gender = _radio.gender or "male" - local _culture = _radio.culture or "en-US" - local _voice = _radio.voice - local _googleTTS = _radio.googleTTS or false - ctld.logTrace(string.format("calling STTS.TextToSpeech(%s)", ctld.p(_shortMessage))) - ctld.logTrace(string.format("_freq=%s", ctld.p(_freq))) - ctld.logTrace(string.format("_modulation=%s", ctld.p(_modulation))) - ctld.logTrace(string.format("_volume=%s", ctld.p(_volume))) - ctld.logTrace(string.format("_name=%s", ctld.p(_name))) - ctld.logTrace(string.format("_gender=%s", ctld.p(_gender))) - ctld.logTrace(string.format("_culture=%s", ctld.p(_culture))) - ctld.logTrace(string.format("_voice=%s", ctld.p(_voice))) - ctld.logTrace(string.format("_googleTTS=%s", ctld.p(_googleTTS))) - STTS.TextToSpeech(_shortMessage, _freq, _modulation, _volume, _name, _side, nil, 1, _gender, _culture, _voice, _googleTTS) - end - - trigger.action.outTextForCoalition(_side, _message, _displayFor) - trigger.action.outSoundForCoalition(_side, "radiobeep.ogg") -end - -function ctld.createSmokeMarker(_enemyUnit, _colour) - - --recreate in 5 mins - ctld.jtacSmokeMarks[_enemyUnit:getName()] = timer.getTime() + 300.0 - - -- move smoke 2 meters above target for ease - local _enemyPoint = _enemyUnit:getPoint() - trigger.action.smoke({ x = _enemyPoint.x, y = _enemyPoint.y + 2.0, z = _enemyPoint.z }, _colour) -end - -function ctld.cancelLase(_jtacGroupName) - - --local index = "JTAC_"..jtacUnit:getID() - - local _tempLase = ctld.jtacLaserPoints[_jtacGroupName] - - if _tempLase ~= nil then - Spot.destroy(_tempLase) - ctld.jtacLaserPoints[_jtacGroupName] = nil - - -- env.info('Destroy laze '..index) - - _tempLase = nil - end - - local _tempIR = ctld.jtacIRPoints[_jtacGroupName] - - if _tempIR ~= nil then - Spot.destroy(_tempIR) - ctld.jtacIRPoints[_jtacGroupName] = nil - - -- env.info('Destroy laze '..index) - - _tempIR = nil - end -end - -function ctld.laseUnit(_enemyUnit, _jtacUnit, _jtacGroupName, _laserCode) - - --cancelLase(jtacGroupName) - - local _spots = {} - - local _enemyVector = _enemyUnit:getPoint() - local _enemyVectorUpdated = { x = _enemyVector.x, y = _enemyVector.y + 2.0, z = _enemyVector.z } - - local _oldLase = ctld.jtacLaserPoints[_jtacGroupName] - local _oldIR = ctld.jtacIRPoints[_jtacGroupName] - - if _oldLase == nil or _oldIR == nil then - - -- create lase - - local _status, _result = pcall(function() - _spots['irPoint'] = Spot.createInfraRed(_jtacUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated) - _spots['laserPoint'] = Spot.createLaser(_jtacUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated, _laserCode) - return _spots - end) - - if not _status then - env.error('ERROR: ' .. _result, false) - else - if _result.irPoint then - - -- env.info(jtacUnit:getName() .. ' placed IR Pointer on '..enemyUnit:getName()) - - ctld.jtacIRPoints[_jtacGroupName] = _result.irPoint --store so we can remove after - end - if _result.laserPoint then - - -- env.info(jtacUnit:getName() .. ' is Lasing '..enemyUnit:getName()..'. CODE:'..laserCode) - - ctld.jtacLaserPoints[_jtacGroupName] = _result.laserPoint - end - end - - else - - -- update lase - - if _oldLase ~= nil then - _oldLase:setPoint(_enemyVectorUpdated) - end - - if _oldIR ~= nil then - _oldIR:setPoint(_enemyVectorUpdated) - end - end -end - --- get currently selected unit and check they're still in range -function ctld.getCurrentUnit(_jtacUnit, _jtacGroupName) - - - local _unit = nil - - if ctld.jtacCurrentTargets[_jtacGroupName] ~= nil then - _unit = Unit.getByName(ctld.jtacCurrentTargets[_jtacGroupName].name) - end - - local _tempPoint = nil - local _tempDist = nil - local _tempPosition = nil - - local _jtacPosition = _jtacUnit:getPosition() - local _jtacPoint = _jtacUnit:getPoint() - - if _unit ~= nil and _unit:getLife() > 0 and _unit:isActive() == true then - - -- calc distance - _tempPoint = _unit:getPoint() - -- tempPosition = unit:getPosition() - - _tempDist = ctld.getDistance(_unit:getPoint(), _jtacUnit:getPoint()) - if _tempDist < ctld.JTAC_maxDistance then - -- calc visible - - -- check slightly above the target as rounding errors can cause issues, plus the unit has some height anyways - local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } - local _offsetJTACPos = { x = _jtacPoint.x, y = _jtacPoint.y + 2.0, z = _jtacPoint.z } - - if land.isVisible(_offsetEnemyPos, _offsetJTACPos) then - return _unit - end - end - end - return nil -end - - --- Find nearest enemy to JTAC that isn't blocked by terrain -function ctld.findNearestVisibleEnemy(_jtacUnit, _targetType,_distance) - - --local startTime = os.clock() - - local _maxDistance = _distance or ctld.JTAC_maxDistance - - local _nearestDistance = _maxDistance - - local _jtacPoint = _jtacUnit:getPoint() - local _coa = _jtacUnit:getCoalition() - - local _offsetJTACPos = { x = _jtacPoint.x, y = _jtacPoint.y + 2.0, z = _jtacPoint.z } - - local _volume = { - id = world.VolumeType.SPHERE, - params = { - point = _offsetJTACPos, - radius = _maxDistance - } - } - - local _unitList = {} - - - local _search = function(_unit, _coa) - pcall(function() - - if _unit ~= nil - and _unit:getLife() > 0 - and _unit:isActive() - and _unit:getCoalition() ~= _coa - and not _unit:inAir() - and not ctld.alreadyTarget(_jtacUnit,_unit) then - - local _tempPoint = _unit:getPoint() - local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } - - if land.isVisible(_offsetJTACPos,_offsetEnemyPos ) then - - local _dist = ctld.getDistance(_offsetJTACPos, _offsetEnemyPos) - - if _dist < _maxDistance then - table.insert(_unitList,{unit=_unit, dist=_dist}) - - end - end - end - end) - - return true - end - - world.searchObjects(Object.Category.UNIT, _volume, _search, _coa) - - --log.info(string.format("JTAC Search elapsed time: %.4f\n", os.clock() - startTime)) - - -- generate list order by distance & visible - - -- first check - -- hpriority - -- priority - -- vehicle - -- unit - - local _sort = function( a,b ) return a.dist < b.dist end - table.sort(_unitList,_sort) - -- sort list - - -- check for hpriority - for _, _enemyUnit in ipairs(_unitList) do - local _enemyName = _enemyUnit.unit:getName() - - if string.match(_enemyName, "hpriority") then - return _enemyUnit.unit - end - end - - for _, _enemyUnit in ipairs(_unitList) do - local _enemyName = _enemyUnit.unit:getName() - - if string.match(_enemyName, "priority") then - return _enemyUnit.unit - end - end - - local result = nil - for _, _enemyUnit in ipairs(_unitList) do - local _enemyName = _enemyUnit.unit:getName() - --log.info(string.format("CTLD - checking _enemyName=%s", _enemyName)) - - -- check for air defenses - --log.info(string.format("CTLD - _enemyUnit.unit:getDesc()[attributes]=%s", ctld.p(_enemyUnit.unit:getDesc()["attributes"]))) - local airdefense = (_enemyUnit.unit:getDesc()["attributes"]["Air Defence"] ~= nil) - --log.info(string.format("CTLD - airdefense=%s", tostring(airdefense))) - - if (_targetType == "vehicle" and ctld.isVehicle(_enemyUnit.unit)) or _targetType == "all" then - if airdefense then - return _enemyUnit.unit - else - result = _enemyUnit.unit - end - - elseif (_targetType == "troop" and ctld.isInfantry(_enemyUnit.unit)) or _targetType == "all" then - if airdefense then - return _enemyUnit.unit - else - result = _enemyUnit.unit - end - end - end - - return result - -end - - -function ctld.listNearbyEnemies(_jtacUnit) - - local _maxDistance = ctld.JTAC_maxDistance - - local _jtacPoint = _jtacUnit:getPoint() - local _coa = _jtacUnit:getCoalition() - - local _offsetJTACPos = { x = _jtacPoint.x, y = _jtacPoint.y + 2.0, z = _jtacPoint.z } - - local _volume = { - id = world.VolumeType.SPHERE, - params = { - point = _offsetJTACPos, - radius = _maxDistance - } - } - local _enemies = nil - - local _search = function(_unit, _coa) - pcall(function() - - if _unit ~= nil - and _unit:getLife() > 0 - and _unit:isActive() - and _unit:getCoalition() ~= _coa - and not _unit:inAir() then - - local _tempPoint = _unit:getPoint() - local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } - - if land.isVisible(_offsetJTACPos,_offsetEnemyPos ) then - - if not _enemies then - _enemies = {} - end - - _enemies[_unit:getTypeName()] = _unit:getTypeName() - - end - end - end) - - return true - end - - world.searchObjects(Object.Category.UNIT, _volume, _search, _coa) - - return _enemies -end - --- tests whether the unit is targeted by another JTAC -function ctld.alreadyTarget(_jtacUnit, _enemyUnit) - - for _, _jtacTarget in pairs(ctld.jtacCurrentTargets) do - - if _jtacTarget.unitId == _enemyUnit:getID() then - -- env.info("ALREADY TARGET") - return true - end - end - - return false -end - - --- Returns only alive units from group but the group / unit may not be active - -function ctld.getGroup(groupName) - - local _groupUnits = Group.getByName(groupName) - - local _filteredUnits = {} --contains alive units - local _x = 1 - - if _groupUnits ~= nil and _groupUnits:isExist() then - - _groupUnits = _groupUnits:getUnits() - - if _groupUnits ~= nil and #_groupUnits > 0 then - for _x = 1, #_groupUnits do - if _groupUnits[_x]:getLife() > 0 then -- removed and _groupUnits[_x]:isExist() as isExist doesnt work on single units! - table.insert(_filteredUnits, _groupUnits[_x]) - end - end - end - end - - return _filteredUnits -end - -function ctld.getAliveGroup(_groupName) - - local _group = Group.getByName(_groupName) - - if _group and _group:isExist() == true and #_group:getUnits() > 0 then - return _group - end - - return nil -end - --- gets the JTAC status and displays to coalition units -function ctld.getJTACStatus(_args) - - --returns the status of all JTAC units - - local _playerUnit = ctld.getTransportUnit(_args[1]) - - if _playerUnit == nil then - return - end - - local _side = _playerUnit:getCoalition() - - local _jtacGroupName = nil - local _jtacUnit = nil - - local _message = "JTAC STATUS: \n\n" - - for _jtacGroupName, _jtacDetails in pairs(ctld.jtacUnits) do - - --look up units - _jtacUnit = Unit.getByName(_jtacDetails.name) - - if _jtacUnit ~= nil and _jtacUnit:getLife() > 0 and _jtacUnit:isActive() == true and _jtacUnit:getCoalition() == _side then - - local _enemyUnit = ctld.getCurrentUnit(_jtacUnit, _jtacGroupName) - - local _laserCode = ctld.jtacLaserPointCodes[_jtacGroupName] - - local _start = _jtacGroupName - if (_jtacDetails.radio) then - _start = _start .. ", available on ".._jtacDetails.radio.freq.." ".._jtacDetails.radio.mod .."," - end - - if _laserCode == nil then - _laserCode = "UNKNOWN" - end - - if _enemyUnit ~= nil and _enemyUnit:getLife() > 0 and _enemyUnit:isActive() == true then - _message = _message .. "" .. _start .. " targeting " .. _enemyUnit:getTypeName() .. " CODE: " .. _laserCode .. ctld.getPositionString(_enemyUnit) .. "\n" - - local _list = ctld.listNearbyEnemies(_jtacUnit) - - if _list then - _message = _message.."Visual On: " - - for _,_type in pairs(_list) do - _message = _message.._type.." " - end - _message = _message.."\n" - end - - else - _message = _message .. "" .. _start .. " searching for targets" .. ctld.getPositionString(_jtacUnit) .. "\n" - end - end - end - - if _message == "JTAC STATUS: \n\n" then - _message = "No Active JTACs" - end - - - ctld.notifyCoalition(_message, 10, _side) -end - - - -function ctld.isInfantry(_unit) - - local _typeName = _unit:getTypeName() - - --type coerce tostring - _typeName = string.lower(_typeName .. "") - - local _soldierType = { "infantry", "paratrooper", "stinger", "manpad", "mortar" } - - for _key, _value in pairs(_soldierType) do - if string.match(_typeName, _value) then - return true - end - end - - return false -end - --- assume anything that isnt soldier is vehicle -function ctld.isVehicle(_unit) - - if ctld.isInfantry(_unit) then - return false - end - - return true -end - --- The entered value can range from 1111 - 1788, --- -- but the first digit of the series must be a 1 or 2 --- -- and the last three digits must be between 1 and 8. --- The range used to be bugged so its not 1 - 8 but 0 - 7. --- function below will use the range 1-7 just incase -function ctld.generateLaserCode() - - ctld.jtacGeneratedLaserCodes = {} - - -- generate list of laser codes - local _code = 1111 - - local _count = 1 - - while _code < 1777 and _count < 30 do - - while true do - - _code = _code + 1 - - if not ctld.containsDigit(_code, 8) - and not ctld.containsDigit(_code, 9) - and not ctld.containsDigit(_code, 0) then - - table.insert(ctld.jtacGeneratedLaserCodes, _code) - - --env.info(_code.." Code") - break - end - end - _count = _count + 1 - end -end - -function ctld.containsDigit(_number, _numberToFind) - - local _thisNumber = _number - local _thisDigit = 0 - - while _thisNumber ~= 0 do - - _thisDigit = _thisNumber % 10 - _thisNumber = math.floor(_thisNumber / 10) - - if _thisDigit == _numberToFind then - return true - end - end - - return false -end - --- 200 - 400 in 10KHz --- 400 - 850 in 10 KHz --- 850 - 1250 in 50 KHz -function ctld.generateVHFrequencies() - - --ignore list - --list of all frequencies in KHZ that could conflict with - -- 191 - 1290 KHz, beacon range - local _skipFrequencies = { - 745, --Astrahan - 381, - 384, - 300.50, - 312.5, - 1175, - 342, - 735, - 300.50, - 353.00, - 440, - 795, - 525, - 520, - 690, - 625, - 291.5, - 300.50, - 435, - 309.50, - 920, - 1065, - 274, - 312.50, - 580, - 602, - 297.50, - 750, - 485, - 950, - 214, - 1025, 730, 995, 455, 307, 670, 329, 395, 770, - 380, 705, 300.5, 507, 740, 1030, 515, - 330, 309.5, - 348, 462, 905, 352, 1210, 942, 435, - 324, - 320, 420, 311, 389, 396, 862, 680, 297.5, - 920, 662, - 866, 907, 309.5, 822, 515, 470, 342, 1182, 309.5, 720, 528, - 337, 312.5, 830, 740, 309.5, 641, 312, 722, 682, 1050, - 1116, 935, 1000, 430, 577, - 326 -- Nevada - } - - ctld.freeVHFFrequencies = {} - local _start = 200000 - - -- first range - while _start < 400000 do - - -- skip existing NDB frequencies - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end - end - - - if _found == false then - table.insert(ctld.freeVHFFrequencies, _start) - end - - _start = _start + 10000 - end - - _start = 400000 - -- second range - while _start < 850000 do - - -- skip existing NDB frequencies - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end - end - - if _found == false then - table.insert(ctld.freeVHFFrequencies, _start) - end - - - _start = _start + 10000 - end - - _start = 850000 - -- third range - while _start <= 1250000 do - - -- skip existing NDB frequencies - local _found = false - for _, value in pairs(_skipFrequencies) do - if value * 1000 == _start then - _found = true - break - end - end - - if _found == false then - table.insert(ctld.freeVHFFrequencies, _start) - end - - _start = _start + 50000 - end -end - --- 220 - 399 MHZ, increments of 0.5MHZ -function ctld.generateUHFrequencies() - - ctld.freeUHFFrequencies = {} - local _start = 220000000 - - while _start < 399000000 do - table.insert(ctld.freeUHFFrequencies, _start) - _start = _start + 500000 - end -end - - --- 220 - 399 MHZ, increments of 0.5MHZ --- -- first digit 3-7MHz --- -- second digit 0-5KHz --- -- third digit 0-9 --- -- fourth digit 0 or 5 --- -- times by 10000 --- -function ctld.generateFMFrequencies() - - ctld.freeFMFrequencies = {} - local _start = 220000000 - - while _start < 399000000 do - - _start = _start + 500000 - end - - for _first = 3, 7 do - for _second = 0, 5 do - for _third = 0, 9 do - local _frequency = ((100 * _first) + (10 * _second) + _third) * 100000 --extra 0 because we didnt bother with 4th digit - table.insert(ctld.freeFMFrequencies, _frequency) - end - end - end -end - -function ctld.getPositionString(_unit) - - if ctld.JTAC_location == false then - return "" - end - - local _lat, _lon = coord.LOtoLL(_unit:getPosition().p) - - local _latLngStr = mist.tostringLL(_lat, _lon, 3, ctld.location_DMS) - - local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_unit:getPosition().p)), 5) - - return " @ " .. _latLngStr .. " - MGRS " .. _mgrsString -end - - --- ***************** SETUP SCRIPT **************** -function ctld.initialize(force) - ctld.logInfo(string.format("Initializing version %s", ctld.Version)) - ctld.logTrace(string.format("ctld.alreadyInitialized=%s", ctld.p(ctld.alreadyInitialized))) - ctld.logTrace(string.format("force=%s", ctld.p(force))) - - if ctld.alreadyInitialized and not force then - ctld.logInfo(string.format("Bypassing initialization because ctld.alreadyInitialized = true")) - return - end - - assert(mist ~= nil, "\n\n** HEY MISSION-DESIGNER! **\n\nMiST has not been loaded!\n\nMake sure MiST 3.6 or higher is running\n*before* running this script!\n") - - ctld.addedTo = {} - ctld.spawnedCratesRED = {} -- use to store crates that have been spawned - ctld.spawnedCratesBLUE = {} -- use to store crates that have been spawned - - ctld.droppedTroopsRED = {} -- stores dropped troop groups - ctld.droppedTroopsBLUE = {} -- stores dropped troop groups - - ctld.droppedVehiclesRED = {} -- stores vehicle groups for c-130 / hercules - ctld.droppedVehiclesBLUE = {} -- stores vehicle groups for c-130 / hercules - - ctld.inTransitTroops = {} - - ctld.inTransitFOBCrates = {} - - ctld.inTransitSlingLoadCrates = {} -- stores crates that are being transported by helicopters for alternative to real slingload - - ctld.droppedFOBCratesRED = {} - ctld.droppedFOBCratesBLUE = {} - - ctld.builtFOBS = {} -- stores fully built fobs - - ctld.completeAASystems = {} -- stores complete spawned groups from multiple crates - - ctld.fobBeacons = {} -- stores FOB radio beacon details, refreshed every 60 seconds - - ctld.deployedRadioBeacons = {} -- stores details of deployed radio beacons - - ctld.beaconCount = 1 - - ctld.usedUHFFrequencies = {} - ctld.usedVHFFrequencies = {} - ctld.usedFMFrequencies = {} - - ctld.freeUHFFrequencies = {} - ctld.freeVHFFrequencies = {} - ctld.freeFMFrequencies = {} - - --used to lookup what the crate will contain - ctld.crateLookupTable = {} - - ctld.extractZones = {} -- stored extract zones - - ctld.missionEditorCargoCrates = {} --crates added by mission editor for triggering cratesinzone - ctld.hoverStatus = {} -- tracks status of a helis hover above a crate - - ctld.callbacks = {} -- function callback - - - -- Remove intransit troops when heli / cargo plane dies - --ctld.eventHandler = {} - --function ctld.eventHandler:onEvent(_event) - -- - -- if _event == nil or _event.initiator == nil then - -- env.info("CTLD null event") - -- elseif _event.id == 9 then - -- -- Pilot dead - -- ctld.inTransitTroops[_event.initiator:getName()] = nil - -- - -- elseif world.event.S_EVENT_EJECTION == _event.id or _event.id == 8 then - -- -- env.info("Event unit - Pilot Ejected or Unit Dead") - -- ctld.inTransitTroops[_event.initiator:getName()] = nil - -- - -- -- env.info(_event.initiator:getName()) - -- end - -- - --end - - -- create crate lookup table - for _subMenuName, _crates in pairs(ctld.spawnableCrates) do - - for _, _crate in pairs(_crates) do - -- convert number to string otherwise we'll have a pointless giant - -- table. String means 'hashmap' so it will only contain the right number of elements - ctld.crateLookupTable[tostring(_crate.weight)] = _crate - end - end - - - --sort out pickup zones - for _, _zone in pairs(ctld.pickupZones) do - - local _zoneName = _zone[1] - local _zoneColor = _zone[2] - local _zoneActive = _zone[4] - - if _zoneColor == "green" then - _zone[2] = trigger.smokeColor.Green - elseif _zoneColor == "red" then - _zone[2] = trigger.smokeColor.Red - elseif _zoneColor == "white" then - _zone[2] = trigger.smokeColor.White - elseif _zoneColor == "orange" then - _zone[2] = trigger.smokeColor.Orange - elseif _zoneColor == "blue" then - _zone[2] = trigger.smokeColor.Blue - else - _zone[2] = -1 -- no smoke colour - end - - -- add in counter for troops or units - if _zone[3] == -1 then - _zone[3] = 10000; - end - - -- change active to 1 / 0 - if _zoneActive == "yes" then - _zone[4] = 1 - else - _zone[4] = 0 - end - end - - --sort out dropoff zones - for _, _zone in pairs(ctld.dropOffZones) do - - local _zoneColor = _zone[2] - - if _zoneColor == "green" then - _zone[2] = trigger.smokeColor.Green - elseif _zoneColor == "red" then - _zone[2] = trigger.smokeColor.Red - elseif _zoneColor == "white" then - _zone[2] = trigger.smokeColor.White - elseif _zoneColor == "orange" then - _zone[2] = trigger.smokeColor.Orange - elseif _zoneColor == "blue" then - _zone[2] = trigger.smokeColor.Blue - else - _zone[2] = -1 -- no smoke colour - end - - --mark as active for refresh smoke logic to work - _zone[4] = 1 - end - - --sort out waypoint zones - for _, _zone in pairs(ctld.wpZones) do - - local _zoneColor = _zone[2] - - if _zoneColor == "green" then - _zone[2] = trigger.smokeColor.Green - elseif _zoneColor == "red" then - _zone[2] = trigger.smokeColor.Red - elseif _zoneColor == "white" then - _zone[2] = trigger.smokeColor.White - elseif _zoneColor == "orange" then - _zone[2] = trigger.smokeColor.Orange - elseif _zoneColor == "blue" then - _zone[2] = trigger.smokeColor.Blue - else - _zone[2] = -1 -- no smoke colour - end - - --mark as active for refresh smoke logic to work - -- change active to 1 / 0 - if _zone[3] == "yes" then - _zone[3] = 1 - else - _zone[3] = 0 - end - end - - -- Sort out extractable groups - for _, _groupName in pairs(ctld.extractableGroups) do - - local _group = Group.getByName(_groupName) - - if _group ~= nil then - - if _group:getCoalition() == 1 then - table.insert(ctld.droppedTroopsRED, _group:getName()) - else - table.insert(ctld.droppedTroopsBLUE, _group:getName()) - end - end - end - - - -- Seperate troop teams into red and blue for random AI pickups - if ctld.allowRandomAiTeamPickups == true then - ctld.redTeams = {} - ctld.blueTeams = {} - for _,_loadGroup in pairs(ctld.loadableGroups) do - if not _loadGroup.side then - table.insert(ctld.redTeams, _) - table.insert(ctld.blueTeams, _) - elseif _loadGroup.side == 1 then - table.insert(ctld.redTeams, _) - elseif _loadGroup.side == 2 then - table.insert(ctld.blueTeams, _) - end - end - end - - -- add total count - - for _,_loadGroup in pairs(ctld.loadableGroups) do - - _loadGroup.total = 0 - if _loadGroup.aa then - _loadGroup.total = _loadGroup.aa + _loadGroup.total - end - - if _loadGroup.inf then - _loadGroup.total = _loadGroup.inf + _loadGroup.total - end - - - if _loadGroup.mg then - _loadGroup.total = _loadGroup.mg + _loadGroup.total - end - - if _loadGroup.at then - _loadGroup.total = _loadGroup.at + _loadGroup.total - end - - if _loadGroup.mortar then - _loadGroup.total = _loadGroup.mortar + _loadGroup.total - end - - end - - - -- Scheduled functions (run cyclically) -- but hold execution for a second so we can override parts - - timer.scheduleFunction(ctld.checkAIStatus, nil, timer.getTime() + 1) - timer.scheduleFunction(ctld.checkTransportStatus, nil, timer.getTime() + 5) - - timer.scheduleFunction(function() - - timer.scheduleFunction(ctld.refreshRadioBeacons, nil, timer.getTime() + 5) - timer.scheduleFunction(ctld.refreshSmoke, nil, timer.getTime() + 5) - timer.scheduleFunction(ctld.addF10MenuOptions, nil, timer.getTime() + 5) - - if ctld.enableCrates == true and ctld.slingLoad == false and ctld.hoverPickup == true then - timer.scheduleFunction(ctld.checkHoverStatus, nil, timer.getTime() + 1) - end - - end,nil, timer.getTime()+1 ) - - --event handler for deaths - --world.addEventHandler(ctld.eventHandler) - - --env.info("CTLD event handler added") - - env.info("Generating Laser Codes") - ctld.generateLaserCode() - env.info("Generated Laser Codes") - - - - env.info("Generating UHF Frequencies") - ctld.generateUHFrequencies() - env.info("Generated UHF Frequencies") - - env.info("Generating VHF Frequencies") - ctld.generateVHFrequencies() - env.info("Generated VHF Frequencies") - - - env.info("Generating FM Frequencies") - ctld.generateFMFrequencies() - env.info("Generated FM Frequencies") - - -- Search for crates - -- Crates are NOT returned by coalition.getStaticObjects() for some reason - -- Search for crates in the mission editor instead - env.info("Searching for Crates") - for _coalitionName, _coalitionData in pairs(env.mission.coalition) do - - if (_coalitionName == 'red' or _coalitionName == 'blue') - and type(_coalitionData) == 'table' then - if _coalitionData.country then --there is a country table - for _, _countryData in pairs(_coalitionData.country) do - - if type(_countryData) == 'table' then - for _objectTypeName, _objectTypeData in pairs(_countryData) do - if _objectTypeName == "static" then - - if ((type(_objectTypeData) == 'table') - and _objectTypeData.group - and (type(_objectTypeData.group) == 'table') - and (#_objectTypeData.group > 0)) then - - for _groupId, _group in pairs(_objectTypeData.group) do - if _group and _group.units and type(_group.units) == 'table' then - for _unitNum, _unit in pairs(_group.units) do - if _unit.canCargo == true then - local _cargoName = env.getValueDictByKey(_unit.name) - ctld.missionEditorCargoCrates[_cargoName] = _cargoName - env.info("Crate Found: " .. _unit.name.." - Unit: ".._cargoName) - end - end - end - end - end - end - end - end - end - end - end - end - env.info("END search for crates") - - -- don't initialize more than once - ctld.alreadyInitialized = true - - env.info("CTLD READY") -end - - --- initialize the random number generator to make it almost random -math.random(); math.random(); math.random() - ---- Enable/Disable error boxes displayed on screen. -env.setErrorMessageBoxEnabled(false) - --- initialize CTLD in 2 seconds, so other scripts have a chance to modify the configuration before initialization -ctld.logInfo(string.format("Loading version %s in 2 seconds", ctld.Version)) -timer.scheduleFunction(ctld.initialize, nil, timer.getTime() + 2) - ---DEBUG FUNCTION --- for key, value in pairs(getmetatable(_spawnedCrate)) do --- env.info(tostring(key)) --- env.info(tostring(value)) --- end diff --git a/resources/plugins/ctld/ctld-config.lua b/resources/plugins/ctld/ctld-config.lua deleted file mode 100644 index 9a057b7ef..000000000 --- a/resources/plugins/ctld/ctld-config.lua +++ /dev/null @@ -1,154 +0,0 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------- --- configuration file for the CTLD Plugin including the JTAC Autolase --- --- This configuration is tailored for a mission generated by DCS Liberation --- see https://github.com/dcs-liberation/dcs_liberation -------------------------------------------------------------------------------------------------------------------------------------------------------------- - -function spawn_crates() - --- CrateSpawn script which needs to be run after CTLD was initialized (3s delay) - env.info("DCSLiberation|CTLD plugin - Spawn crates") - for _, crate in pairs(dcsLiberation.Logistics.crates) do - ctld.spawnCrateAtZone(crate.coalition, tonumber(crate.weight), crate.zone) - end -end - -function preload_troops(preload_data) - --- Troop loading script which needs to be run after CTLD was initialized (5s delay) - env.info(string.format("DCSLiberation|CTLD plugin - Preloading Troops into %s", preload_data["unit"])) - ctld.preLoadTransport(preload_data["unit"], preload_data["amount"], true) -end - -function toboolean(str) return str == "true" end - --- CTLD plugin - configuration -if dcsLiberation then - local ctld_pickup_smoke = "none" - local ctld_dropoff_smoke = "none" - - -- JTACAutoLase specific options - local autolase = false - local smoke = false - local fc3LaserCode = false - - -- retrieve specific options values - if dcsLiberation.plugins then - if dcsLiberation.plugins.ctld then - env.info("DCSLiberation|CTLD plugin - Setting Up") - --- Debug Settings - ctld.Debug = dcsLiberation.plugins.ctld.debug - ctld.Trace = dcsLiberation.plugins.ctld.debug - - -- Sling loadings settings - ctld.enableCrates = true - ctld.slingLoad = dcsLiberation.plugins.ctld.slingload - ctld.staticBugFix = not dcsLiberation.plugins.ctld.slingload - - --- Special unitLoad Settings as proposed in #2174 - ctld.maximumDistanceLogistic = 300 - ctld.unitLoadLimits = {} - ctld.unitActions = {} - for _, transport in pairs(dcsLiberation.Logistics.transports) do - ctld.unitLoadLimits[transport.aircraft_type] = tonumber(transport.cabin_size) - ctld.unitActions[transport.aircraft_type] = { crates = toboolean(transport.crates), troops = toboolean(transport.troops) } - end - - if dcsLiberation.plugins.ctld.smoke then - ctld_pickup_smoke = "blue" - ctld_dropoff_smoke = "green" - end - - -- Definition of spawnable things - local ctld_troops = ctld.loadableGroups - ctld.loadableGroups = { - { name = "Liberation Troops (2)", inf = 2 }, - { name = "Liberation Troops (4)", inf = 4 }, - { name = "Liberation Troops (6)", inf = 4, mg = 1, at = 1 }, - { name = "Liberation Troops (10)", inf = 5, mg = 2, at = 2, aa = 1 }, - { name = "Liberation Troops (12)", inf = 6, mg = 2, at = 2, aa = 2 }, - { name = "Liberation Troops (24)", inf = 12, mg = 4, at = 4, aa = 3, jtac = 1 }, - } - if dcsLiberation.plugins.ctld.tailorctld then - --- remove all default CTLD spawning settings - --- so that we can tailor them for the tasked missions - ctld.enableSmokeDrop = false - ctld.enabledRadioBeaconDrop = false - ctld.spawnableCrates = {} - ctld.vehiclesForTransportRED = {} - ctld.vehiclesForTransportBLUE = {} - ctld.transportPilotNames = {} - ctld.logisticUnits = {} - ctld.pickupZones = {} - ctld.dropOffZones = {} - ctld.wpZones = {} - else - --- append the default CTLD troops - for _, troop in pairs(ctld_troops) do - table.insert(ctld.loadableGroups, troop) - end - end - - --- add all carriers as pickup zone - if dcsLiberation.Carriers then - for _, carrier in pairs(dcsLiberation.Carriers) do - table.insert(ctld.pickupZones, { carrier.unit_name, ctld_pickup_smoke, -1, "yes", 0 }) - end - end - - --- generate mission specific spawnable crates - local spawnable_crates = {} - for _, crate in pairs(dcsLiberation.Logistics.spawnable_crates) do - table.insert(spawnable_crates, { weight = tonumber(crate.weight), desc = crate.unit, unit = crate.unit }) - end - ctld.spawnableCrates["Liberation Crates"] = spawnable_crates - - --- Parse the LogisticsInfo for the mission - for _, item in pairs(dcsLiberation.Logistics.flights) do - for _, pilot in pairs(item.pilot_names) do - table.insert(ctld.transportPilotNames, pilot) - if toboolean(item.preload) then - local amount = ctld.unitLoadLimits[item.aircraft_type] - timer.scheduleFunction(preload_troops, { unit = pilot, amount = amount }, timer.getTime() + 5) - end - end - if item.pickup_zone then - table.insert(ctld.pickupZones, { item.pickup_zone, ctld_pickup_smoke, -1, "yes", tonumber(item.side) }) - end - if item.drop_off_zone then - table.insert(ctld.dropOffZones, { item.drop_off_zone, ctld_dropoff_smoke, tonumber(item.side) }) - end - if item.target_zone then - table.insert(ctld.wpZones, { item.target_zone, "none", "yes", tonumber(item.side) }) - end - if dcsLiberation.plugins.ctld.logisticunit and item.logistic_unit then - table.insert(ctld.logisticUnits, item.logistic_unit) - end - end - - autolase = dcsLiberation.plugins.ctld.autolase - env.info(string.format("DCSLiberation|CTLD plugin - JTAC AutoLase enabled = %s", tostring(autolase))) - - if autolase then - smoke = dcsLiberation.plugins.ctld.jtacsmoke - env.info(string.format("DCSLiberation|CTLD plugin - JTACAutolase smoke = %s", tostring(smoke))) - - fc3LaserCode = dcsLiberation.plugins.ctld.fc3LaserCode - env.info(string.format("DCSLiberation|CTLD plugin - JTACAutolase fc3LaserCode = %s", tostring(fc3LaserCode))) - - -- JTAC Autolase configuration code - for _, jtac in pairs(dcsLiberation.JTACs) do - env.info(string.format("DCSLiberation|JTACAutolase - setting up %s", jtac.dcsGroupName)) - if fc3LaserCode then - -- If fc3LaserCode is enabled in the plugin configuration, force the JTAC - -- laser code to 1113 to allow lasing for Su-25 Frogfoots and A-10A Warthogs. - jtac.laserCode = 1113 - end - ctld.JTACAutoLase(jtac.dcsGroupName, jtac.laserCode, smoke, 'vehicle', nil, { freq = jtac.radio, mod = jtac.modulation, name = jtac.dcsGroupName }) - end - end - if dcsLiberation.plugins.ctld.airliftcrates then - timer.scheduleFunction(spawn_crates, nil, timer.getTime() + 3) - end - end - end -end diff --git a/resources/plugins/ctld/plugin.json b/resources/plugins/ctld/plugin.json deleted file mode 100644 index d50c8e85c..000000000 --- a/resources/plugins/ctld/plugin.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "nameInUI": "CTLD", - "defaultValue": true, - "specificOptions": [ - { - "nameInUI": "Tailor CTLD for the Liberation specific missions", - "mnemonic": "tailorctld", - "defaultValue": true - }, - { - "nameInUI": "Create logistic unit in each pickup zone", - "mnemonic": "logisticunit", - "defaultValue": true - }, - { - "nameInUI": "CTLD Use smoke in zones", - "mnemonic": "smoke", - "defaultValue": true - }, - { - "nameInUI": "Automatically spawn crates for airlift", - "mnemonic": "airliftcrates", - "defaultValue": false - }, - { - "nameInUI": "Use real sling loading", - "mnemonic": "slingload", - "defaultValue": false - }, - { - "nameInUI": "JTAC Autolase", - "mnemonic": "autolase", - "defaultValue": true - }, - { - "nameInUI": "JTAC Use smoke", - "mnemonic": "jtacsmoke", - "defaultValue": true - }, - { - "nameInUI": "JTAC Use FC3 laser code (1113)", - "mnemonic": "fc3LaserCode", - "defaultValue": false - }, - { - "nameInUI": "CTLD Debug", - "mnemonic": "debug", - "defaultValue": false - } - ], - "scriptsWorkOrders": [ - { - "file": "CTLD.lua", - "mnemonic": "ctld-script" - } - ], - "configurationWorkOrders": [ - { - "file": "ctld-config.lua", - "mnemonic": "ctld-config" - } - ] -} \ No newline at end of file diff --git a/resources/plugins/ewrs/LICENSE b/resources/plugins/ewrs/LICENSE deleted file mode 100644 index 765904328..000000000 --- a/resources/plugins/ewrs/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Bob7heBuilder - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/resources/plugins/ewrs/ewrs.lua b/resources/plugins/ewrs/ewrs.lua deleted file mode 100644 index a70c18065..000000000 --- a/resources/plugins/ewrs/ewrs.lua +++ /dev/null @@ -1,831 +0,0 @@ ---[[ - Early Warning Radar Script - 1.5.3 - 07/11/2016 - - Allows use of units with radars to provide Bearing Range and Altitude information via text display to player aircraft - - Features: - - Uses in-game radar information to detect targets so terrain masking, beaming, low altitude flying, etc is effective for avoiding detection - - Dynamic. If valid units with radar are created during a mission (eg. via chopper with CTLD), they will be added to the EWRS radar network - - Can allow / disable BRA messages to fighters or sides - - Uses player aircraft or mission bullseye for BRA reference, can be changed via F10 radio menu or restricted to one reference in the script settings - - Can switch between imperial (feet, knots, NM) or metric (meters, km/h, km) measurements using F10 radio menu - - Ability to change the message display time and automated update interval - - Can choose to disable automated messages and allow players to request BRA from F10 menu - - Can allow players to request Bogey Dope at any time through F10 radio menu - - Built and Tested in DCS 1.5 - See https://github.com/Bob7heBuilder/EWRS for the latest version - - This script uses MIST 4.0.57 or later - https://github.com/mrSkortch/MissionScriptingTools - - At the moment, because of limitations within DCS to not show messages to individual units, the reference, measurements, and messages - are done per group. So a group of 4 fighters will each receive 4 BRA messages. Each message however, will have the player's name - in it, that its refering to. Its unfortunate, but nothing I can do about it. - - Changes: - - 1.3 - Added Option to allow picture report to be requested thru F10 menu instead of an automated display - - Fixed bug where a known unit type would sometimes still display as ??? - - 1.4 - Added setting to be able to limit the amount of threats displayed in a picture report - - Added option to enable Bogey Dopes - * Mission designer can turn on / off in script settings - * Pilots can request thru the F10 menu and it will show the BRA to the nearest hostile aircraft that has - been detected. It will always reference the requesting pilot's own aircraft. - - Finally implemented a cleaner workaround for some ground units being detected and listed in picture report - - 1.4.1 - Added some ships to search radar list, you will need to remove the comment markers (--) at the start of the line to activate - - 1.5 - Added ability to request picture of friendly aircraft positions referencing your own aircraft - Mission designer chooses if this feature is active or not - - 1.5.1 - Added Gazelle to acCategories - - 1.5.2 - Added F5E to acCategories - - 1.5.3 - Fixed bug with maxThreatDisplay set at 0 not displaying any threats - - Added Mistral Gazelle - - Added C-101CC -]] - -ewrs = {} --DO NOT REMOVE -ewrs.HELO = 1 -ewrs.ATTACK = 2 -ewrs.FIGHTER = 3 - -----SCRIPT OPTIONS---- - -ewrs.messageUpdateInterval = 30 --How often EWRS will update automated BRA messages (seconds) -ewrs.messageDisplayTime = 25 --How long EWRS BRA messages will show for (seconds) -ewrs.restrictToOneReference = false -- Disables the ability to change the BRA calls from pilot's own aircraft or bullseye. If this is true, set ewrs.defaultReference to the option you want to restrict to. -ewrs.defaultReference = "self" --The default reference for BRA calls - can be changed via f10 radio menu if ewrs.restrictToOneReference is false (self or bulls) -ewrs.defaultMeasurements = "imperial" --Default measurement units - can be changed via f10 radio menu (imperial or metric) -ewrs.disableFightersBRA = false -- disables BRA messages to fighters when true -ewrs.enableRedTeam = true -- enables / disables EWRS for the red team -ewrs.enableBlueTeam = true -- enables / disables EWRS for the blue team -ewrs.disableMessageWhenNoThreats = true -- disables message when no threats are detected - Thanks Rivvern - NOTE: If using ewrs.onDemand = true, this has no effect -ewrs.useImprovedDetectionLogic = true --this makes the messages more realistic. If the radar doesn't know the type or distance to the detected threat, it will be reflected in the picture report / BRA message -ewrs.onDemand = false --Setting to true will disable the automated messages to everyone and will add an F10 menu to get picture / BRA message. -ewrs.maxThreatDisplay = 5 -- Max amounts of threats to display on picture report (0 will display all) -ewrs.allowBogeyDope = true -- Allows pilots to request a bogey dope even with the automated messages running. It will display only the cloest threat, and will always reference the players own aircraft. -ewrs.allowFriendlyPicture = true -- Allows pilots to request picture of friendly aircraft -ewrs.maxFriendlyDisplay = 5 -- Limits the amount of friendly aircraft shown on friendly picture - ---[[ -Units with radar to use as part of the EWRS radar network -If you want to shorten the range of SAM radar detection, use their track radars instead of their search radars -NOTE that track radars require a search radar to detect targets (but the search radars do not need to be included in the list) -I haven't tested detection with ships (that have radar), but should work. -]] -ewrs.validSearchRadars = { -"p-10 s125 sr", --SA-3 Search Radar -"Kub 1S91 str", --SA-6 Search and Track Radar -"S-300PS 64H6E sr", --SA-10 Search Radar -"S-300 PS 40B6MD sr", --SA-10 Search Radar -"SA-11 Buk SR 9518M1", --SA-11 Search Radar -"55G6 EWR", --Early Warning Radar -"1L13 EWR", --Early Warning Radar -"A-50", --AWACS -"E-2D", --AWACS -"E-3A", --AWACS -"Roland Radar", --Roland Search Radar -"Hawk sr", --Hawk SAM Search Radar -"Patriot str", --Patriot SAM Search and Track Radar - ---Ships - I've left these commented out because I don't know which ones have radar ---and which ones don't. Just remove the comment to activate them (the '--' at the start of the line) - ---"MOSCOW", -- CG 1164 Moskva ---"TICONDEROG", -- CG-60 Normandy ---"PIOTR", -- CGN 1144.2 Pyotr Velikiy ---"KUZNECOW", -- CV 1143.5 Admiral Kuzentsov ---"VINSON", -- CVN-70 Carl Vinson ---"REZKY", -- FF 1135M Rezky ---"NEUSTRASH", -- FFG 11540 Neustrashimy ---"PERRY", -- FFG-7CL Oliver Hazzard Perry ---"ALBATROS", -- FFL 1124.4 Grisha ---"MOLNIYA", -- FSG 1241.1MP Molniya -} - ---[[ -Aircraft Type ENUMs -This is used to restrict BRA messages to fighters -Change the ewrs.TYPE for each aircraft (in ewrs.acCategories) to suit your needs -For now, BRA will be displayed to everyone unless ewrs.disableFightersBRA is true. -When this is true, anything in the list below that == ewrs.FIGHTER will NOT receive BRA messages -]] -ewrs.acCategories = { --Have I left anything out? Please let me know if I have -[ "A-10A" ] = ewrs.ATTACK , -[ "A-10C" ] = ewrs.ATTACK , -[ "Bf-109K-4" ] = ewrs.ATTACK , -[ "C-101EB" ] = ewrs.ATTACK , -[ "C-101CC" ] = ewrs.ATTACK , -[ "F-15C" ] = ewrs.FIGHTER , -[ "F-5E-3" ] = ewrs.ATTACK , -[ "FW-190D9" ] = ewrs.ATTACK , -[ "F-86F Sabre" ] = ewrs.FIGHTER , -[ "Hawk" ] = ewrs.ATTACK , -[ "Ka-50" ] = ewrs.HELO , -[ "L-39C" ] = ewrs.ATTACK , -[ "L-39ZA" ] = ewrs.ATTACK , -[ "Mi-8MT" ] = ewrs.HELO , -[ "MiG-15bis" ] = ewrs.ATTACK , -[ "MiG-21Bis" ] = ewrs.ATTACK , -[ "MiG-29A" ] = ewrs.FIGHTER , -[ "MiG-29S" ] = ewrs.FIGHTER , -[ "M-2000C" ] = ewrs.FIGHTER , -[ "P-51D" ] = ewrs.ATTACK , -[ "SA342M" ] = ewrs.HELO , -[ "SA342L" ] = ewrs.HELO , -[ "SA342Mistral" ] = ewrs.HELO , -[ "Su-25" ] = ewrs.ATTACK , -[ "Su-25T" ] = ewrs.ATTACK , -[ "Su-27" ] = ewrs.FIGHTER , -[ "Su-33" ] = ewrs.FIGHTER , -[ "TF-51D" ] = ewrs.ATTACK , -[ "UH-1H" ] = ewrs.HELO , -[ "J-11A" ] = ewrs.FIGHTER , -} - -----END OF SCRIPT OPTIONS---- - - -----INTERNAL FUNCTIONS ***** Be Careful changing things below here ***** ---- - - -function ewrs.getDistance(obj1PosX, obj1PosZ, obj2PosX, obj2PosZ) - local xDiff = obj1PosX - obj2PosX - local yDiff = obj1PosZ - obj2PosZ - return math.sqrt(xDiff * xDiff + yDiff * yDiff) -- meters -end - -function ewrs.getBearing(obj1PosX, obj1PosZ, obj2PosX, obj2PosZ) - local bearing = math.atan2(obj2PosZ - obj1PosZ, obj2PosX - obj1PosX) - if bearing < 0 then - bearing = bearing + 2 * math.pi - end - bearing = bearing * 180 / math.pi - return bearing -- degrees -end - -function ewrs.getHeading(vec) - local heading = math.atan2(vec.z,vec.x) - if heading < 0 then - heading = heading + 2 * math.pi - end - heading = heading * 180 / math.pi - return heading -- degrees -end - -function ewrs.getSpeed(velocity) - local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2) --m/s - return speed -- m/s -end - -function ewrs.update() - timer.scheduleFunction(ewrs.update, nil, timer.getTime() + 5) - ewrs.buildActivePlayers() - ewrs.buildF10Menu() -end - -function ewrs.buildThreatTable(activePlayer, bogeyDope) - local function sortRanges(v1,v2) - return v1.range < v2.range - end - - local targets = {} - if activePlayer.side == 2 then - targets = ewrs.currentlyDetectedRedUnits - else - targets = ewrs.currentlyDetectedBlueUnits - end - - local bogeyDope = bogeyDope or false - local referenceX - local referenceZ - if ewrs.groupSettings[tostring(activePlayer.groupID)].reference == "self" or bogeyDope then - local _self = Unit.getByName(activePlayer.unitname) - local selfpos = _self:getPosition() - referenceX = selfpos.p.x - referenceZ = selfpos.p.z - else - local bullseye = coalition.getMainRefPoint(activePlayer.side) - referenceX = bullseye.x - referenceZ = bullseye.z - end - - local threatTable = {} - - for k,v in pairs(targets) do - local velocity = v["object"]:getVelocity() - local bogeypos = v["object"]:getPosition() - local bogeyType = nil - if ewrs.useImprovedDetectionLogic then - if v["type"] then - bogeyType = v["object"]:getTypeName() - else - bogeyType = " ??? " - end - else - bogeyType = v["object"]:getTypeName() - end - - local bearing = ewrs.getBearing(referenceX,referenceZ,bogeypos.p.x,bogeypos.p.z) - local heading = ewrs.getHeading(velocity) - local range = ewrs.getDistance(referenceX,referenceZ,bogeypos.p.x,bogeypos.p.z) -- meters - local altitude = bogeypos.p.y --meters - local speed = ewrs.getSpeed(velocity) --m/s - - if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then - range = range / 1000 --change to KM - speed = mist.utils.mpsToKmph(speed) - --altitude already in meters - else - range = mist.utils.metersToNM(range) - speed = mist.utils.mpsToKnots(speed) - altitude = mist.utils.metersToFeet(altitude) - end - - if ewrs.useImprovedDetectionLogic then - if not v["distance"] then - range = ewrs.notAvailable - end - end - - local j = #threatTable + 1 - threatTable[j] = {} - threatTable[j].unitType = bogeyType - threatTable[j].bearing = bearing - threatTable[j].range = range - threatTable[j].altitude = altitude - threatTable[j].speed = speed - threatTable[j].heading = heading - end - - table.sort(threatTable,sortRanges) - - return threatTable -end - -function ewrs.outText(activePlayer, threatTable, bogeyDope, greeting) - local status, result = pcall(function() - - local message = {} - local altUnits - local speedUnits - local rangeUnits - local bogeyDope = bogeyDope or false - if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then - altUnits = "m" - speedUnits = "Km/h" - rangeUnits = "Km" - else - altUnits = "ft" - speedUnits = "Knts" - rangeUnits = "NM" - end - - if #threatTable >= 1 then - local maxThreats = nil - local messageGreeting = nil - if greeting == nil then - if bogeyDope then - maxThreats = 1 - messageGreeting = "EWRS Bogey Dope for: " .. activePlayer.player - else - if ewrs.maxThreatDisplay == 0 then - maxThreats = 999 - else - maxThreats = ewrs.maxThreatDisplay - end - messageGreeting = "EWRS Picture Report for: " .. activePlayer.player .. " -- Reference: " .. ewrs.groupSettings[tostring(activePlayer.groupID)].reference - end - else - messageGreeting = greeting - maxThreats = ewrs.maxFriendlyDisplay - end - - --Display table - table.insert(message, "\n") - table.insert(message, messageGreeting) - table.insert(message, "\n\n") - table.insert(message, string.format( "%-16s", "TYPE")) - table.insert(message, string.format( "%-12s", "BRG")) - table.insert(message, string.format( "%-12s", "RNG")) - table.insert(message, string.format( "%-21s", "ALT")) - table.insert(message, string.format( "%-15s", "SPD")) - table.insert(message, string.format( "%-3s", "HDG")) - table.insert(message, "\n") - - for k = 1, maxThreats do - if threatTable[k] == nil then break end - table.insert(message, "\n") - table.insert(message, string.format( "%-16s", threatTable[k].unitType)) - if threatTable[k].range == ewrs.notAvailable then - table.insert(message, string.format( "%-12s", " ")) - table.insert(message, string.format( "%-12s", "POSITION")) - table.insert(message, string.format( "%-21s", " ")) - table.insert(message, string.format( "%-15s", "UNKNOWN")) - table.insert(message, string.format( "%-3s", " ")) - else - table.insert(message, string.format( "%03d", threatTable[k].bearing)) - table.insert(message, string.format( "%8.1f %s", threatTable[k].range, rangeUnits)) - table.insert(message, string.format( "%9d %s", threatTable[k].altitude, altUnits)) - table.insert(message, string.format( "%9d %s", threatTable[k].speed, speedUnits)) - table.insert(message, string.format( " %03d", threatTable[k].heading)) - end - table.insert(message, "\n") - end - trigger.action.outTextForGroup(activePlayer.groupID, table.concat(message), ewrs.messageDisplayTime) - else - if (not ewrs.disableMessageWhenNoThreats) or (ewrs.onDemand) and greeting == nil then - trigger.action.outTextForGroup(activePlayer.groupID, "\nEWRS Picture Report for: " .. activePlayer.player .. "\n\nNo targets detected", ewrs.messageDisplayTime) - end - if greeting ~= nil then - trigger.action.outTextForGroup(activePlayer.groupID, "\nEWRS Friendly Picture for: " .. activePlayer.player .. "\n\nNo friendlies detected", ewrs.messageDisplayTime) - end - end - end) - if not status then - env.error(string.format("EWRS outText Error: %s", result)) - end -end - -function ewrs.displayMessageToAll() - local status, result = pcall(function() - timer.scheduleFunction(ewrs.displayMessageToAll, nil, timer.getTime() + ewrs.messageUpdateInterval) - ewrs.findRadarUnits() - ewrs.getDetectedTargets() - for i = 1, #ewrs.activePlayers do - if ewrs.groupSettings[tostring(ewrs.activePlayers[i].groupID)].messages then - if ewrs.activePlayers[i].side == 1 and #ewrs.redEwrUnits > 0 or ewrs.activePlayers[i].side == 2 and #ewrs.blueEwrUnits > 0 then - ewrs.outText(ewrs.activePlayers[i], ewrs.buildThreatTable(ewrs.activePlayers[i])) - end -- if ewrs.activePlayers[i].side == 1 and #ewrs.redEwrUnits > 0 or ewrs.activePlayers[i].side == 2 and #ewrs.blueEwrUnits > 0 then - end -- if ewrs.groupSettings[tostring(ewrs.activePlayers[i].groupID)].messages then - end -- for i = 1, #ewrs.activePlayers do - end) - if not status then - env.error(string.format("EWRS displayMessageToAll Error: %s", result)) - end -end - -function ewrs.onDemandMessage(args) - local status, result = pcall(function() - ewrs.findRadarUnits() - ewrs.getDetectedTargets() - for i = 1, #ewrs.activePlayers do - if ewrs.activePlayers[i].groupID == args[1] then - ewrs.outText(ewrs.activePlayers[i], ewrs.buildThreatTable(ewrs.activePlayers[i],args[2]),args[2]) - end - end - end) - if not status then - env.error(string.format("EWRS onDemandMessage Error: %s", result)) - end -end - -function ewrs.buildFriendlyTable(friendlyNames,activePlayer) - local function sortRanges(v1,v2) - return v1.range < v2.range - end - - local units = {} - for i =1, #friendlyNames do - local unit = Unit.getByName(friendlyNames[i]) - if unit ~= nil and unit:isActive() then - - table.insert(units,unit) - else - --env.error("Friendly Picture - Unit not found: "..friendlyNames[i]) -- Client Planes that are not active will fall into here. - end - end - - local _self = Unit.getByName(activePlayer.unitname) - local selfpos = _self:getPosition() - local referenceX = selfpos.p.x - local referenceZ = selfpos.p.z - - local friendlyTable = {} - - for k,v in pairs(units) do - local velocity = v:getVelocity() - local pos = v:getPosition() - local bogeyType = v:getTypeName() - if pos.p.x ~= selfpos.p.x and pos.p.z ~= selfpos.p.z then --same position as self, means its you! - - local bearing = ewrs.getBearing(referenceX,referenceZ,pos.p.x,pos.p.z) - local heading = ewrs.getHeading(velocity) - local range = ewrs.getDistance(referenceX,referenceZ,pos.p.x,pos.p.z) -- meters - local altitude = pos.p.y --meters - local speed = ewrs.getSpeed(velocity) --m/s - - if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then - range = range / 1000 --change to KM - speed = mist.utils.mpsToKmph(speed) - --altitude already in meters - else - range = mist.utils.metersToNM(range) - speed = mist.utils.mpsToKnots(speed) - altitude = mist.utils.metersToFeet(altitude) - end - - local j = #friendlyTable + 1 - friendlyTable[j] = {} - friendlyTable[j].unitType = bogeyType - friendlyTable[j].bearing = bearing - friendlyTable[j].range = range - friendlyTable[j].altitude = altitude - friendlyTable[j].speed = speed - friendlyTable[j].heading = heading - else - --env.info("Friendly Picture - Found Self") - end - end - - table.sort(friendlyTable,sortRanges) - - return friendlyTable -end - -function ewrs.friendlyPicture(args) - local status, result = pcall(function() - for i = 1, #ewrs.activePlayers do - if ewrs.activePlayers[i].groupID == args[1] then - local sideString = nil - if ewrs.activePlayers[i].side == 1 then - sideString = "[red]" - else - sideString = "[blue]" - end - local filter = {sideString.."[helicopter]", sideString.."[plane]"} - local friendlies = mist.makeUnitTable(filter) --find a way to do this only once if there is more then 1 person in a group - local friendlyTable = ewrs.buildFriendlyTable(friendlies,ewrs.activePlayers[i]) - local greeting = "EWRS Friendly Picture for: " .. ewrs.activePlayers[i].player - ewrs.outText(ewrs.activePlayers[i],friendlyTable,false,greeting) - end - end - end) - if not status then - env.error(string.format("EWRS friendlyPicture Error: %s", result)) - end -end - -function ewrs.buildActivePlayers() - local status, result = pcall(function() - local filter = { "[all][plane]","[all][helicopter]"} - local all_vecs = mist.makeUnitTable(filter) - ewrs.activePlayers = {} - for i = 1, #all_vecs do - local vec = Unit.getByName(all_vecs[i]) - if vec ~= nil and Unit.isActive(vec) then - playerName = Unit.getPlayerName(vec) - local groupID = ewrs.getGroupId(vec) - if playerName ~= nil then - unitCategory = ewrs.acCategories[Unit.getTypeName(vec)] - if ewrs.disableFightersBRA and unitCategory == ewrs.FIGHTER then - --DONT DO ANYTHING - else - local group = Unit.getGroup(vec) - if ewrs.enableBlueTeam and Unit.getCoalition(vec) == 2 then - ewrs.addPlayer(playerName, groupID, vec) - elseif ewrs.enableRedTeam and Unit.getCoalition(vec) == 1 then - ewrs.addPlayer(playerName, groupID, vec) - end - end - end - end - end - end) -- pcall - - if not status then - env.error(string.format("EWRS buildActivePlayers Error: %s", result)) - end -end - ---THANK YOU ciribob http://forums.eagle.ru/showpost.php?p=2499638&postcount=5 ---And Stonehouse for pointing me there -function ewrs.getGroupId(_unit) --Temp fix for client groups not being accessable - - local _unitDB = mist.DBs.unitsById[tonumber(_unit:getID())] - if _unitDB ~= nil and _unitDB.groupId then - return _unitDB.groupId - end - - return nil -end - -function ewrs.getGroupCategory(unit) - local unitDB = mist.DBs.unitsById[tonumber(unit:getID())] - if unitDB ~= nil and unitDB.category then - return unitDB.category - end - - return nil -end - -function ewrs.addPlayer(playerName, groupID, unit ) - local status, result = pcall(function() - local i = #ewrs.activePlayers + 1 - ewrs.activePlayers[i] = {} - ewrs.activePlayers[i].player = playerName - ewrs.activePlayers[i].groupID = groupID - ewrs.activePlayers[i].unitname = unit:getName() - ewrs.activePlayers[i].side = unit:getCoalition() - - -- add default settings to settings table if it hasn't been done yet - if ewrs.groupSettings[tostring(groupID)] == nil then - ewrs.addGroupSettings(tostring(groupID)) - end - end) - if not status then - env.error(string.format("EWRS addPlayer Error: %s", result)) - end -end - --- filters units so ones detected by multiple radar sites still only get listed once --- Filters out anything that isn't a plane or helicopter -function ewrs.filterUnits(units) - local newUnits = {} - for k,v in pairs(units) do - local valid = true - if v["object"]:getCategory() ~= Object.Category.UNIT then --rare but i've had it detect missiles - valid = false - end - if valid then --another check cause it seems AI radar can detected some ground units - local category = ewrs.getGroupCategory(v["object"]) - if category ~= "plane" and category ~= "helicopter" then valid = false end - end - - if valid then - for nk,nv in pairs (newUnits) do --recursive loop, can't see a way around this - if v["object"]:getName() == nv["object"]:getName() then - valid = false - --update already found unit incase the first detection(s) didn't know type or distance - if v["type"] then - nv["type"] = true - end - if v["distance"] then - nv["distance"] = true - end - end - end - end - - if valid then - table.insert(newUnits, v) - end - end - return newUnits -end - -function ewrs.getDetectedTargets() - if #ewrs.blueEwrUnits > 0 then - ewrs.currentlyDetectedRedUnits = ewrs.findDetectedTargets("red") - end - if #ewrs.redEwrUnits > 0 then - ewrs.currentlyDetectedBlueUnits = ewrs.findDetectedTargets("blue") - end -end - -function ewrs.findDetectedTargets(side) - local units = {} - local ewrUnits = {} - - if side == "red" then - ewrUnits = ewrs.blueEwrUnits - elseif side == "blue" then - ewrUnits = ewrs.redEwrUnits - end - - for n = 1, #ewrUnits do - local ewrUnit = Unit.getByName(ewrUnits[n]) - if ewrUnit ~= nil then - local ewrControl = ewrUnit:getGroup():getController() - local detectedTargets = ewrControl:getDetectedTargets(Controller.Detection.RADAR) - for k,v in pairs (detectedTargets) do - table.insert(units, v) - end - end - end - return ewrs.filterUnits(units) -end - -function ewrs.findRadarUnits() - local filter = {} - if ewrs.enableBlueTeam and ewrs.enableRedTeam then - filter = { "[all][plane]", "[all][vehicle]", "[all][ship]"} - elseif ewrs.enableBlueTeam then - filter = { "[blue][plane]", "[blue][vehicle]", "[blue][ship]"} - elseif ewrs.enableRedTeam then - filter = { "[red][plane]", "[red][vehicle]", "[red][ship]"} - end - local all_vecs = mist.makeUnitTable(filter) - local redUnits = {} - local blueUnits = {} - - for i = 1, #all_vecs do - local vec = Unit.getByName(all_vecs[i]) - - if vec ~= nil then - if Unit.isActive(vec) then - local vec_type = Unit.getTypeName(vec) - for n = 1, #ewrs.validSearchRadars do - if ewrs.validSearchRadars[n] == vec_type and Unit.getCoalition(vec) == 2 then - table.insert(blueUnits, Unit.getName(vec)) - break - end - if ewrs.validSearchRadars[n] == vec_type and Unit.getCoalition(vec) == 1 then - table.insert(redUnits, Unit.getName(vec)) - break - end - end --for n = 1, #ewrs.validSearchRadars do - end --if Unit.isActive(vec) then - end --if vec ~= nil then - end --for i = 1, #all_vecs do - ewrs.blueEwrUnits = blueUnits - ewrs.redEwrUnits = redUnits -end - -function ewrs.addGroupSettings(groupID) - ewrs.groupSettings[groupID] = {} - ewrs.groupSettings[groupID].reference = ewrs.defaultReference - ewrs.groupSettings[groupID].measurements = ewrs.defaultMeasurements - ewrs.groupSettings[groupID].messages = true -end - -function ewrs.setGroupReference(args) - local groupID = args[1] - ewrs.groupSettings[tostring(groupID)].reference = args[2] - trigger.action.outTextForGroup(groupID,"Reference changed to "..args[2],ewrs.messageDisplayTime) -end - -function ewrs.setGroupMeasurements(args) - local groupID = args[1] - ewrs.groupSettings[tostring(groupID)].measurements = args[2] - trigger.action.outTextForGroup(groupID,"Measurement units changed to "..args[2],ewrs.messageDisplayTime) -end - -function ewrs.setGroupMessages(args) - local groupID = args[1] - local onOff - if args[2] then onOff = "on" else onOff = "off" end - ewrs.groupSettings[tostring(groupID)].messages = args[2] - trigger.action.outTextForGroup(groupID,"Picture reports for group turned "..onOff,ewrs.messageDisplayTime) -end - -function ewrs.buildF10Menu() - local status, result = pcall(function() - for i = 1, #ewrs.activePlayers do - local groupID = ewrs.activePlayers[i].groupID - local stringGroupID = tostring(groupID) - if ewrs.builtF10Menus[stringGroupID] == nil then - local rootPath = missionCommands.addSubMenuForGroup(groupID, "EWRS") - - if ewrs.allowBogeyDope then - missionCommands.addCommandForGroup(groupID, "Request Bogey Dope",rootPath,ewrs.onDemandMessage,{groupID,true}) - end - - if ewrs.onDemand then - missionCommands.addCommandForGroup(groupID, "Request Picture",rootPath,ewrs.onDemandMessage,{groupID}) - end - - if ewrs.allowFriendlyPicture then - missionCommands.addCommandForGroup(groupID, "Request Friendly Picture",rootPath,ewrs.friendlyPicture,{groupID}) - end - - if not ewrs.restrictToOneReference then - local referenceSetPath = missionCommands.addSubMenuForGroup(groupID,"Set GROUP's reference point", rootPath) - missionCommands.addCommandForGroup(groupID, "Set to Bullseye",referenceSetPath,ewrs.setGroupReference,{groupID, "bulls"}) - missionCommands.addCommandForGroup(groupID, "Set to Self",referenceSetPath,ewrs.setGroupReference,{groupID, "self"}) - end - - local measurementsSetPath = missionCommands.addSubMenuForGroup(groupID,"Set GROUP's measurement units",rootPath) - missionCommands.addCommandForGroup(groupID, "Set to Imperial (feet, knts)",measurementsSetPath,ewrs.setGroupMeasurements,{groupID, "imperial"}) - missionCommands.addCommandForGroup(groupID, "Set to Metric (meters, km/h)",measurementsSetPath,ewrs.setGroupMeasurements,{groupID, "metric"}) - - if not ewrs.onDemand then - local messageOnOffPath = missionCommands.addSubMenuForGroup(groupID, "Turn Picture Report On/Off",rootPath) - missionCommands.addCommandForGroup(groupID, "Message ON", messageOnOffPath, ewrs.setGroupMessages, {groupID, true}) - missionCommands.addCommandForGroup(groupID, "Message OFF", messageOnOffPath, ewrs.setGroupMessages, {groupID, false}) - end - - ewrs.builtF10Menus[stringGroupID] = true - end - end - end) - - if not status then - env.error(string.format("EWRS buildF10Menu Error: %s", result)) - end -end - ---temp fix for ground units being detected by radar - FIXED ---[[ Leaving this here just in case I introduce threat based filtering, saves me writing it again -ewrs.validThreats = { -["A-10A"] = true, -["A-10C"] = true, -["A-50"] = true, -["AH-1W"] = true, -["AH-64A"] = true, -["AH-64D"] = true, -["An-26B"] = true, -["An-30M"] = true, -["B-1B"] = true, -["B-52H"] = true, -["Bf-109K-4"] = true, -["C-101CC"] = true, -["C-101EB"] = true, -["C-130"] = true, -["C-17A"] = true, -["CH-47D"] = true, -["CH-53E"] = true, -["E-2D"] = true, -["E-2C"] = true, -["E-3A"] = true, -["F-111F"] = true, -["F-117A"] = true, -["F-14A"] = true, -["F-15C"] = true, -["F-15E"] = true, -["F-16A"] = true, -["F-16A MLU"] = true, -["F-16C bl.50"] = true, -["F-16C bl.52d"] = true, -["F-4E"] = true, -["F-5E"] = true, -["F-5E-3"] = true, -["F-86F Sabre"] = true, -["F/A-18A"] = true, -["F/A-18C"] = true, -["FW-190D9"] = true, -["Hawk"] = true, -["IL-76MD"] = true, -["IL-78M"] = true, -["KC-135"] = true, -["Ka-27"] = true, -["Ka-50"] = true, -["Ka-52"] = true, -["L-39C"] = true, -["L-39ZA"] = true, -["M-2000C"] = true, -["MQ-9 Reaper"] = true, -["Mi-24V"] = true, -["Mi-26"] = true, -["Mi-28N"] = true, -["Mi-8MT"] = true, -["MiG-15bis"] = true, -["MiG-21Bis"] = true, -["MiG-23MLD"] = true, -["MiG-25PD"] = true, -["MiG-25RBT"] = true, -["MiG-27K"] = true, -["MiG-29A"] = true, -["MiG-29G"] = true, -["MiG-29K"] = true, -["MiG-29S"] = true, -["MiG-31"] = true, -["Mirage 2000-5"] = true, -["OH-58D"] = true, -["P-51D"] = true, -["RQ-1A Predator"] = true, -["S-3B"] = true, -["S-3B Tanker"] = true, -["SH-3W"] = true, -["SH-60B"] = true, -["Su-17M4"] = true, -["Su-24M"] = true, -["Su-24MR"] = true, -["Su-25"] = true, -["Su-25T"] = true, -["Su-25TM"] = true, -["Su-27"] = true, -["Su-30"] = true, -["Su-33"] = true, -["Su-34"] = true, -["TF-51D"] = true, -["Tornado GR4"] = true, -["Tornado IDS"] = true, -["Tu-142"] = true, -["Tu-160"] = true, -["Tu-22M3"] = true, -["Tu-95MS"] = true, -["UH-1H"] = true, -["UH-60A"] = true, -["Yak-40"] = true, -} -]] - ---SCRIPT INIT -ewrs.currentlyDetectedRedUnits = {} -ewrs.currentlyDetectedBlueUnits = {} -ewrs.redEwrUnits = {} -ewrs.blueEwrUnits = {} -ewrs.activePlayers = {} -ewrs.groupSettings = {} -ewrs.builtF10Menus = {} -ewrs.notAvailable = 999999 - -ewrs.update() -if not ewrs.onDemand then - timer.scheduleFunction(ewrs.displayMessageToAll, nil, timer.getTime() + ewrs.messageUpdateInterval) -end -trigger.action.outText("EWRS by Steggles is now running",15) -env.info("EWRS Running") - ---[[ -TODO: - - Add check on friendly picture to not give one if no AWACS / EWR units are active. Doesn't use radar info anyway. Maybe just leave it to help out people with SA? Feedback Please!! - - Clean up functions and arguments from bogeyDope and friendly picture additions - - Threat based filtering if theres interest. -]] \ No newline at end of file diff --git a/resources/plugins/ewrs/plugin.json b/resources/plugins/ewrs/plugin.json deleted file mode 100644 index 8787db14f..000000000 --- a/resources/plugins/ewrs/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "nameInUI": "EWRS", - "defaultValue": false, - "specificOptions": [], - "scriptsWorkOrders": [ - { - "file": "ewrs.lua", - "mnemonic": "ewrs" - } - ], - "configurationWorkOrders": [] -} \ No newline at end of file diff --git a/resources/plugins/herculescargo/Hercules_Cargo.lua b/resources/plugins/herculescargo/Hercules_Cargo.lua deleted file mode 100644 index 1a534cf22..000000000 --- a/resources/plugins/herculescargo/Hercules_Cargo.lua +++ /dev/null @@ -1,686 +0,0 @@ - --- Hercules Cargo Drop Events by Anubis Yinepu - --- This script will only work for the Herculus mod by Anubis --- Payloads carried by pylons 11, 12 and 13 need to be declared in the Herculus_Loadout.lua file --- Except for Ammo pallets, this script will spawn whatever payload gets launched from pylons 11, 12 and 13 --- Pylons 11, 12 and 13 are moveable within the Herculus cargobay area --- Ammo pallets can only be jettisoned from these pylons with no benefit to DCS world --- To benefit DCS world, Ammo pallets need to be off/on loaded using DCS arming and refueling window --- Cargo_Container_Enclosed = true: Cargo enclosed in container with parachute, need to be dropped from 100m (300ft) or more, except when parked on ground --- Cargo_Container_Enclosed = false: Open cargo with no parachute, need to be dropped from 10m (30ft) or less - -Hercules_Cargo = {} -Hercules_Cargo.Hercules_Cargo_Drop_Events = {} -local GT_DisplayName = "" -local GT_Name = "" -local Cargo_Drop_initiator = "" -local Cargo_Container_Enclosed = false -local SoldierGroup = false -local ParatrooperCount = 1 -local ParatrooperGroupSpawnInit = false -local ParatrooperGroupSpawn = false - -local Herc_j = 0 -local Herc_Cargo = {} -Herc_Cargo.Cargo_Drop_Direction = 0 -Herc_Cargo.Cargo_Contents = "" -Herc_Cargo.Cargo_Type_name = "" -Herc_Cargo.Cargo_over_water = false -Herc_Cargo.Container_Enclosed = false -Herc_Cargo.offload_cargo = false -Herc_Cargo.all_cargo_survive_to_the_ground = false -Herc_Cargo.all_cargo_gets_destroyed = false -Herc_Cargo.destroy_cargo_dropped_without_parachute = false -Herc_Cargo.scheduleFunctionID = 0 - -local CargoHeading = 0 -local Cargo_Drop_Position = {} - -local SoldierUnitID = 12000 -local SoldierGroupID = 12000 -local GroupSpacing = 0 ---added by wrench -Hercules_Cargo.types = { - ["ATGM M1045 HMMWV TOW Air [7183lb]"] = {['name'] = "M1045 HMMWV TOW", ['container'] = true}, - ["ATGM M1045 HMMWV TOW Skid [7073lb]"] = {['name'] = "M1045 HMMWV TOW", ['container'] = false}, - ["APC M1043 HMMWV Armament Air [7023lb]"] = {['name'] = "M1043 HMMWV Armament", ['container'] = true}, - ["APC M1043 HMMWV Armament Skid [6912lb]"] = {['name'] = "M1043 HMMWV Armament", ['container'] = false}, - ["SAM Avenger M1097 Air [7200lb]"] = {['name'] = "M1097 Avenger", ['container'] = true}, - ["SAM Avenger M1097 Skid [7090lb]"] = {['name'] = "M1097 Avenger", ['container'] = false}, - ["APC Cobra Air [10912lb]"] = {['name'] = "Cobra", ['container'] = true}, - ["APC Cobra Skid [10802lb]"] = {['name'] = "Cobra", ['container'] = false}, - ["APC M113 Air [21624lb]"] = {['name'] = "M-113", ['container'] = true}, - ["APC M113 Skid [21494lb]"] = {['name'] = "M-113", ['container'] = false}, - ["Tanker M978 HEMTT [34000lb]"] = {['name'] = "M978 HEMTT Tanker", ['container'] = false}, - ["HEMTT TFFT [34400lb]"] = {['name'] = "HEMTT TFFT", ['container'] = false}, - ["SPG M1128 Stryker MGS [33036lb]"] = {['name'] = "M1128 Stryker MGS", ['container'] = false}, - ["AAA Vulcan M163 Air [21666lb]"] = {['name'] = "Vulcan", ['container'] = true}, - ["AAA Vulcan M163 Skid [21577lb]"] = {['name'] = "Vulcan", ['container'] = false}, - ["APC M1126 Stryker ICV [29542lb]"] = {['name'] = "M1126 Stryker ICV", ['container'] = false}, - ["ATGM M1134 Stryker [30337lb]"] = {['name'] = "M1134 Stryker ATGM", ['container'] = false}, - ["APC LAV-25 Air [22520lb]"] = {['name'] = "LAV-25", ['container'] = true}, - ["APC LAV-25 Skid [22514lb]"] = {['name'] = "LAV-25", ['container'] = false}, - ["M1025 HMMWV Air [6160lb]"] = {['name'] = "Hummer", ['container'] = true}, - ["M1025 HMMWV Skid [6050lb]"] = {['name'] = "Hummer", ['container'] = false}, - ["IFV M2A2 Bradley [34720lb]"] = {['name'] = "M-2 Bradley", ['container'] = false}, - ["IFV MCV-80 [34720lb]"] = {['name'] = "MCV-80", ['container'] = false}, - ["IFV BMP-1 [23232lb]"] = {['name'] = "BMP-1", ['container'] = false}, - ["IFV BMP-2 [25168lb]"] = {['name'] = "BMP-2", ['container'] = false}, - ["IFV BMP-3 [32912lb]"] = {['name'] = "BMP-3", ['container'] = false}, - ["ARV BRDM-2 Air [12320lb]"] = {['name'] = "BRDM-2", ['container'] = true}, - ["ARV BRDM-2 Skid [12210lb]"] = {['name'] = "BRDM-2", ['container'] = false}, - ["APC BTR-80 Air [23936lb]"] = {['name'] = "BTR-80", ['container'] = true}, - ["APC BTR-80 Skid [23826lb]"] = {['name'] = "BTR-80", ['container'] = false}, - ["APC BTR-82A Air [24998lb]"] = {['name'] = "BTR-82A", ['container'] = true}, - ["APC BTR-82A Skid [24888lb]"] = {['name'] = "BTR-82A", ['container'] = false}, - ["SAM ROLAND ADS [34720lb]"] = {['name'] = "Roland Radar", ['container'] = false}, - ["SAM ROLAND LN [34720b]"] = {['name'] = "Roland ADS", ['container'] = false}, - ["SAM SA-13 STRELA [21624lb]"] = {['name'] = "Strela-10M3", ['container'] = false}, - ["AAA ZSU-23-4 Shilka [32912lb]"] = {['name'] = "ZSU-23-4 Shilka", ['container'] = false}, - ["SAM SA-19 Tunguska 2S6 [34720lb]"] = {['name'] = "2S6 Tunguska", ['container'] = false}, - ["Transport UAZ-469 Air [3747lb]"] = {['name'] = "UAZ-469", ['container'] = true}, - ["Transport UAZ-469 Skid [3630lb]"] = {['name'] = "UAZ-469", ['container'] = false}, - ["AAA GEPARD [34720lb]"] = {['name'] = "Gepard", ['container'] = false}, - ["SAM CHAPARRAL Air [21624lb]"] = {['name'] = "M48 Chaparral", ['container'] = true}, - ["SAM CHAPARRAL Skid [21516lb]"] = {['name'] = "M48 Chaparral", ['container'] = false}, - ["SAM LINEBACKER [34720lb]"] = {['name'] = "M6 Linebacker", ['container'] = false}, - ["Transport URAL-375 [14815lb]"] = {['name'] = "Ural-375", ['container'] = false}, - ["Transport M818 [16000lb]"] = {['name'] = "M 818", ['container'] = false}, - ["IFV MARDER [34720lb]"] = {['name'] = "Marder", ['container'] = false}, - ["Transport Tigr Air [15900lb]"] = {['name'] = "Tigr_233036", ['container'] = true}, - ["Transport Tigr Skid [15730lb]"] = {['name'] = "Tigr_233036", ['container'] = false}, - ["IFV TPZ FUCH [33440lb]"] = {['name'] = "TPZ", ['container'] = false}, - ["IFV BMD-1 Air [18040lb]"] = {['name'] = "BMD-1", ['container'] = true}, - ["IFV BMD-1 Skid [17930lb]"] = {['name'] = "BMD-1", ['container'] = false}, - ["IFV BTR-D Air [18040lb]"] = {['name'] = "BTR_D", ['container'] = true}, - ["IFV BTR-D Skid [17930lb]"] = {['name'] = "BTR_D", ['container'] = false}, - ["EWR SBORKA Air [21624lb]"] = {['name'] = "Dog Ear radar", ['container'] = true}, - ["EWR SBORKA Skid [21624lb]"] = {['name'] = "Dog Ear radar", ['container'] = false}, - ["ART 2S9 NONA Air [19140lb]"] = {['name'] = "SAU 2-C9", ['container'] = true}, - ["ART 2S9 NONA Skid [19030lb]"] = {['name'] = "SAU 2-C9", ['container'] = false}, - ["ART GVOZDIKA [34720lb]"] = {['name'] = "SAU Gvozdika", ['container'] = false}, - ["APC MTLB Air [26400lb]"] = {['name'] = "MTLB", ['container'] = true}, - ["APC MTLB Skid [26290lb]"] = {['name'] = "MTLB", ['container'] = false}, - --["Generic Crate [20000lb]"] = {['name'] = "Hercules_Container_Parachute", ['container'] = true} -} -function Hercules_Cargo.Soldier_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, GroupSpacing) - SoldierUnitID = SoldierUnitID + 30 - SoldierGroupID = SoldierGroupID + 1 - local Herc_Soldier_Spawn = - { - ["visible"] = false, - ["tasks"] = - { - }, -- end of ["tasks"] - ["uncontrollable"] = false, - ["task"] = "Ground Nothing", - ["taskSelected"] = true, - ["groupId"] = SoldierGroupID, - ["hidden"] = false, - ["units"] = - { - [1] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 0.5 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 0.5 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [1] - [2] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 1.0 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 1.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [2] - [3] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 1.5 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 1.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [3] - [4] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 2.0 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 2.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [4] - [5] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 2.5 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 2.5 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [5] - [6] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 3.0 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 3.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [6] - [7] = - { - ["type"] = "Soldier M249", - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 3.5 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 3.5 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [7] - [8] = - { - ["type"] = "Soldier M249", - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 4.0 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 4.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [8] - [9] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 4.5 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 4.5 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [9] - [10] = - { - ["type"] = "Paratrooper RPG-16", - ["transportable"] = - { - ["randomTransportable"] = true, - }, -- end of ["transportable"] - ["unitId"] = SoldierUnitID + 1, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z + 5.0 + GroupSpacing, - ["x"] = Cargo_Drop_Position.x + 5.0 + GroupSpacing, - ["name"] = "Soldier Unit "..SoldierUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = false, - }, -- end of [10] - }, -- end of ["units"] - ["y"] = Cargo_Drop_Position.z, - ["x"] = Cargo_Drop_Position.x, - ["name"] = "Soldier_Group_"..SoldierGroupID, - ["start_time"] = 0, - } - coalition.addGroup(Cargo_Country, Group.Category.GROUND, Herc_Soldier_Spawn) -end - -local CargoUnitID = 10000 -local CargoGroupID = 10000 -local CargoStaticGroupID = 11000 - -function Hercules_Cargo.Cargo_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country) - CargoUnitID = CargoUnitID + 1 - CargoGroupID = CargoGroupID + 1 - local Herc_Cargo_Spawn = - { - ["visible"] = false, - ["tasks"] = - { - }, -- end of ["tasks"] - ["uncontrollable"] = false, - ["task"] = "Ground Nothing", - ["groupId"] = CargoGroupID, - ["hidden"] = false, - ["units"] = - { - [1] = - { - ["type"] = Cargo_Type_name, - ["transportable"] = - { - ["randomTransportable"] = false, - }, -- end of ["transportable"] - ["unitId"] = CargoUnitID, - ["skill"] = "Excellent", - ["y"] = Cargo_Drop_Position.z, - ["x"] = Cargo_Drop_Position.x, - ["name"] = "Cargo Unit "..CargoUnitID, - ["heading"] = CargoHeading, - ["playerCanDrive"] = true, - }, -- end of [1] - }, -- end of ["units"] - ["y"] = Cargo_Drop_Position.z, - ["x"] = Cargo_Drop_Position.x, - ["name"] = "Cargo Group "..CargoUnitID, - ["start_time"] = 0, - } - coalition.addGroup(Cargo_Country, Group.Category.GROUND, Herc_Cargo_Spawn) -end - -function Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, dead, Cargo_Country) - CargoStaticGroupID = CargoStaticGroupID + 1 - local Herc_CargoObject_Spawn = - { - ["type"] = Cargo_Type_name, - ["y"] = Cargo_Drop_Position.z, - ["x"] = Cargo_Drop_Position.x, - ["name"] = "Cargo Static Group "..CargoStaticGroupID, - ["heading"] = CargoHeading, - ["dead"] = dead, - } - coalition.addStaticObject(Cargo_Country, Herc_CargoObject_Spawn) -end - -function Hercules_Cargo.Cargo_SpawnObjects(Cargo_Drop_Direction, Cargo_Content_position, Cargo_Type_name, Cargo_over_water, Container_Enclosed, ParatrooperGroupSpawn, offload_cargo, all_cargo_survive_to_the_ground, all_cargo_gets_destroyed, destroy_cargo_dropped_without_parachute, Cargo_Country) - if offload_cargo == true then - ------------------------------------------------------------------------------ - if CargoHeading >= 3.14 then - CargoHeading = 0 - Cargo_Drop_Position = {["x"] = Cargo_Content_position.x - (30.0 * math.cos(Cargo_Drop_Direction - 1.0)), - ["z"] = Cargo_Content_position.z - (30.0 * math.sin(Cargo_Drop_Direction - 1.0))} - else - if CargoHeading >= 1.57 then - CargoHeading = 3.14 - Cargo_Drop_Position = {["x"] = Cargo_Content_position.x - (20.0 * math.cos(Cargo_Drop_Direction + 0.5)), - ["z"] = Cargo_Content_position.z - (20.0 * math.sin(Cargo_Drop_Direction + 0.5))} - else - if CargoHeading >= 0 then - CargoHeading = 1.57 - Cargo_Drop_Position = {["x"] = Cargo_Content_position.x - (10.0 * math.cos(Cargo_Drop_Direction + 1.5)), - ["z"] = Cargo_Content_position.z - (10.0 * math.sin(Cargo_Drop_Direction + 1.5))} - end - end - end - ------------------------------------------------------------------------------ - if ParatrooperGroupSpawn == true then - Hercules_Cargo.Soldier_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, 0) - Hercules_Cargo.Soldier_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, 5) - Hercules_Cargo.Soldier_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, 10) - else - Hercules_Cargo.Cargo_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, 0) - end - else - ------------------------------------------------------------------------------ - CargoHeading = 0 - Cargo_Drop_Position = {["x"] = Cargo_Content_position.x - (20.0 * math.cos(Cargo_Drop_Direction)), - ["z"] = Cargo_Content_position.z - (20.0 * math.cos(Cargo_Drop_Direction))} - ------------------------------------------------------------------------------ - if all_cargo_gets_destroyed == true or Cargo_over_water == true then - if Container_Enclosed == true then - Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, true, Cargo_Country) - if ParatrooperGroupSpawn == false then - Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, "Hercules_Container_Parachute_Static", CargoHeading, true, Cargo_Country) - end - else - Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, true, Cargo_Country) - end - else - ------------------------------------------------------------------------------ - if all_cargo_survive_to_the_ground == true then - if ParatrooperGroupSpawn == true then - Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, true, Cargo_Country) - else - Hercules_Cargo.Cargo_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country) - end - if Container_Enclosed == true then - if ParatrooperGroupSpawn == false then - Hercules_Cargo.Cargo_SpawnStatic({["z"] = Cargo_Drop_Position.z + 10.0,["x"] = Cargo_Drop_Position.x + 10.0}, "Hercules_Container_Parachute_Static", CargoHeading, false, Cargo_Country) - end - end - end - ------------------------------------------------------------------------------ - if destroy_cargo_dropped_without_parachute == true then - if Container_Enclosed == true then - if ParatrooperGroupSpawn == true then - Hercules_Cargo.Soldier_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country, 0) - else - Hercules_Cargo.Cargo_SpawnGroup(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, Cargo_Country) - Hercules_Cargo.Cargo_SpawnStatic({["z"] = Cargo_Drop_Position.z + 10.0,["x"] = Cargo_Drop_Position.x + 10.0}, "Hercules_Container_Parachute_Static", CargoHeading, false, Cargo_Country) - end - else - Hercules_Cargo.Cargo_SpawnStatic(Cargo_Drop_Position, Cargo_Type_name, CargoHeading, true, Cargo_Country) - end - end - ------------------------------------------------------------------------------ - end - end -end - -function Hercules_Cargo.Calculate_Object_Height_AGL(object) - return object:getPosition().p.y - land.getHeight({x = object:getPosition().p.x, y = object:getPosition().p.z}) -end - -function Hercules_Cargo.Check_SurfaceType(object) - -- LAND,--1 SHALLOW_WATER,--2 WATER,--3 ROAD,--4 RUNWAY--5 - return land.getSurfaceType({x = object:getPosition().p.x, y = object:getPosition().p.z}) -end - -function Hercules_Cargo.Cargo_Track(Arg, time) - local status, result = pcall( - function() - local next = next - if next(Arg[1].Cargo_Contents) ~= nil then - if Hercules_Cargo.Calculate_Object_Height_AGL(Arg[1].Cargo_Contents) < 5.0 then--pallet less than 5m above ground before spawning - if Hercules_Cargo.Check_SurfaceType(Arg[1].Cargo_Contents) == 2 or Hercules_Cargo.Check_SurfaceType(Arg[1].Cargo_Contents) == 3 then - Arg[1].Cargo_over_water = true--pallets gets destroyed in water - end - Arg[1].Cargo_Contents:destroy()--remove pallet+parachute before hitting ground and replace with Cargo_SpawnContents - Hercules_Cargo.Cargo_SpawnObjects(Arg[1].Cargo_Drop_Direction, Object.getPoint(Arg[1].Cargo_Contents), Arg[1].Cargo_Type_name, Arg[1].Cargo_over_water, Arg[1].Container_Enclosed, Arg[1].ParatrooperGroupSpawn, Arg[1].offload_cargo, Arg[1].all_cargo_survive_to_the_ground, Arg[1].all_cargo_gets_destroyed, Arg[1].destroy_cargo_dropped_without_parachute, Arg[1].Cargo_Country) - timer.removeFunction(Arg[1].scheduleFunctionID) - Arg[1] = {} - end - return time + 0.1 - end - end) -- pcall - if not status then - -- env.error(string.format("Cargo_Spawn: %s", result)) - else - return result - end -end - -function Hercules_Cargo.Calculate_Cargo_Drop_initiator_NorthCorrection(point) --correction needed for true north - if not point.z then --Vec2; convert to Vec3 - point.z = point.y - point.y = 0 - end - local lat, lon = coord.LOtoLL(point) - local north_posit = coord.LLtoLO(lat + 1, lon) - return math.atan2(north_posit.z - point.z, north_posit.x - point.x) -end - -function Hercules_Cargo.Calculate_Cargo_Drop_initiator_Heading(Cargo_Drop_initiator) - local Heading = math.atan2(Cargo_Drop_initiator:getPosition().x.z, Cargo_Drop_initiator:getPosition().x.x) - Heading = Heading + Hercules_Cargo.Calculate_Cargo_Drop_initiator_NorthCorrection(Cargo_Drop_initiator:getPosition().p) - if Heading < 0 then - Heading = Heading + (2 * math.pi)-- put heading in range of 0 to 2*pi - end - return Heading + 0.06 -- rad -end - -function Hercules_Cargo.Cargo_Initialize(initiator, Cargo_Contents, Cargo_Type_name, Container_Enclosed) - local status, result = pcall( - function() - Cargo_Drop_initiator = Unit.getByName(initiator:getName()) - local next = next - if next(Cargo_Drop_initiator) ~= nil then - if ParatrooperGroupSpawnInit == true then - if (ParatrooperCount == 1 or ParatrooperCount == 2 or ParatrooperCount == 3) then - Herc_j = Herc_j + 1 - Herc_Cargo[Herc_j] = {} - Herc_Cargo[Herc_j].Cargo_Drop_Direction = Hercules_Cargo.Calculate_Cargo_Drop_initiator_Heading(Cargo_Drop_initiator) - Herc_Cargo[Herc_j].Cargo_Contents = Cargo_Contents - Herc_Cargo[Herc_j].Cargo_Type_name = Cargo_Type_name - Herc_Cargo[Herc_j].Container_Enclosed = Container_Enclosed - Herc_Cargo[Herc_j].ParatrooperGroupSpawn = ParatrooperGroupSpawnInit - Herc_Cargo[Herc_j].Cargo_Country = initiator:getCountry() - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 5.0 then--aircraft on ground - Herc_Cargo[Herc_j].offload_cargo = true - ParatrooperCount = 0 - ParatrooperGroupSpawnInit = false - else - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 10.0 then--aircraft less than 10m above ground - Herc_Cargo[Herc_j].all_cargo_survive_to_the_ground = true - else - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 100.0 then--aircraft more than 10m but less than 100m above ground - Herc_Cargo[Herc_j].all_cargo_gets_destroyed = true - else - ------------------------------------------------------------------------------ - Herc_Cargo[Herc_j].destroy_cargo_dropped_without_parachute = true--aircraft more than 100m above ground - end - end - end - ------------------------------------------------------------------------------ - Herc_Cargo[Herc_j].scheduleFunctionID = timer.scheduleFunction(Hercules_Cargo.Cargo_Track, {Herc_Cargo[Herc_j]}, timer.getTime() + 0.1) - ParatrooperCount = ParatrooperCount + 1.0 - else - if (ParatrooperCount == 30) then - ParatrooperGroupSpawnInit = false - ParatrooperCount = 1 - else - ParatrooperCount = ParatrooperCount + 1.0 - end - end - else - Herc_j = Herc_j + 1 - Herc_Cargo[Herc_j] = {} - Herc_Cargo[Herc_j].Cargo_Drop_Direction = Hercules_Cargo.Calculate_Cargo_Drop_initiator_Heading(Cargo_Drop_initiator) - Herc_Cargo[Herc_j].Cargo_Contents = Cargo_Contents - Herc_Cargo[Herc_j].Cargo_Type_name = Cargo_Type_name - Herc_Cargo[Herc_j].Container_Enclosed = Container_Enclosed - Herc_Cargo[Herc_j].ParatrooperGroupSpawn = ParatrooperGroupSpawnInit - Herc_Cargo[Herc_j].Cargo_Country = initiator:getCountry() - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 5.0 then--aircraft on ground - Herc_Cargo[Herc_j].offload_cargo = true - else - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 10.0 then--aircraft less than 10m above ground - Herc_Cargo[Herc_j].all_cargo_survive_to_the_ground = true - else - ------------------------------------------------------------------------------ - if Hercules_Cargo.Calculate_Object_Height_AGL(Cargo_Drop_initiator) < 100.0 then--aircraft more than 10m but less than 100m above ground - Herc_Cargo[Herc_j].all_cargo_gets_destroyed = true - else - ------------------------------------------------------------------------------ - Herc_Cargo[Herc_j].destroy_cargo_dropped_without_parachute = true--aircraft more than 100m above ground - end - end - end - ------------------------------------------------------------------------------ - Herc_Cargo[Herc_j].scheduleFunctionID = timer.scheduleFunction(Hercules_Cargo.Cargo_Track, {Herc_Cargo[Herc_j]}, timer.getTime() + 0.1) - end - end - end) -- pcall - if not status then - -- env.error(string.format("Cargo_Initialize: %s", result)) - else - return result - end -end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - -- EventHandlers ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -function Hercules_Cargo.Hercules_Cargo_Drop_Events:onEvent(Cargo_Drop_Event) - if Cargo_Drop_Event.id == world.event.S_EVENT_SHOT then - GT_DisplayName = Weapon.getDesc(Cargo_Drop_Event.weapon).typeName:sub(15, -1)--Remove "weapons.bombs." from string - -- trigger.action.outTextForCoalition(coalition.side.BLUE, string.format("Cargo_Drop_Event: %s", Weapon.getDesc(Cargo_Drop_Event.weapon).typeName), 10) - -- trigger.action.outTextForCoalition(coalition.side.RED, string.format("Cargo_Drop_Event: %s", Weapon.getDesc(Cargo_Drop_Event.weapon).typeName), 10) - --------------------------------------------------------------------------------------------------------------------------------- - if (GT_DisplayName == "Squad 30 x Soldier [7950lb]") then - GT_Name = "Soldier M4 GRG" - SoldierGroup = true - ParatrooperGroupSpawnInit = true - Hercules_Cargo.Cargo_Initialize(Cargo_Drop_Event.initiator, Cargo_Drop_Event.weapon, GT_Name, SoldierGroup) - end - --------------------------------------------------------------------------------------------------------------------------------- - if Hercules_Cargo.types[GT_DisplayName] then - local GT_Name = Hercules_Cargo.types[GT_DisplayName]['name'] - local Cargo_Container_Enclosed = Hercules_Cargo.types[GT_DisplayName]['container'] - Hercules_Cargo.Cargo_Initialize(Cargo_Drop_Event.initiator, Cargo_Drop_Event.weapon, GT_Name, Cargo_Container_Enclosed) - end -end -end -world.addEventHandler(Hercules_Cargo.Hercules_Cargo_Drop_Events) - --- trigger.action.outTextForCoalition(coalition.side.BLUE, string.format("Cargo_Drop_Event.weapon: %s", Weapon.getDesc(Cargo_Drop_Event.weapon).typeName), 10) --- trigger.action.outTextForCoalition(coalition.side.BLUE, tostring('Calculate_Object_Height_AGL: ' .. aaaaa), 10) --- trigger.action.outTextForCoalition(coalition.side.BLUE, string.format("Speed: %.2f", Calculate_Object_Speed(Cargo_Drop_initiator)), 10) --- trigger.action.outTextForCoalition(coalition.side.BLUE, string.format("Russian Interceptor Patrol scrambled from Nalchik"), 10) - --- function basicSerialize(var) - -- if var == nil then - -- return "\"\"" - -- else - -- if ((type(var) == 'number') or - -- (type(var) == 'boolean') or - -- (type(var) == 'function') or - -- (type(var) == 'table') or - -- (type(var) == 'userdata') ) then - -- return tostring(var) - -- else - -- if type(var) == 'string' then - -- var = string.format('%q', var) - -- return var - -- end - -- end - -- end --- end - --- function tableShow(tbl, loc, indent, tableshow_tbls) --based on serialize_slmod, this is a _G serialization - -- tableshow_tbls = tableshow_tbls or {} --create table of tables - -- loc = loc or "" - -- indent = indent or "" - -- if type(tbl) == 'table' then --function only works for tables! - -- tableshow_tbls[tbl] = loc - -- local tbl_str = {} - -- tbl_str[#tbl_str + 1] = indent .. '{\n' - -- for ind,val in pairs(tbl) do -- serialize its fields - -- if type(ind) == "number" then - -- tbl_str[#tbl_str + 1] = indent - -- tbl_str[#tbl_str + 1] = loc .. '[' - -- tbl_str[#tbl_str + 1] = tostring(ind) - -- tbl_str[#tbl_str + 1] = '] = ' - -- else - -- tbl_str[#tbl_str + 1] = indent - -- tbl_str[#tbl_str + 1] = loc .. '[' - -- tbl_str[#tbl_str + 1] = basicSerialize(ind) - -- tbl_str[#tbl_str + 1] = '] = ' - -- end - -- if ((type(val) == 'number') or (type(val) == 'boolean')) then - -- tbl_str[#tbl_str + 1] = tostring(val) - -- tbl_str[#tbl_str + 1] = ',\n' - -- elseif type(val) == 'string' then - -- tbl_str[#tbl_str + 1] = basicSerialize(val) - -- tbl_str[#tbl_str + 1] = ',\n' - -- elseif type(val) == 'nil' then -- won't ever happen, right? - -- tbl_str[#tbl_str + 1] = 'nil,\n' - -- elseif type(val) == 'table' then - -- if tableshow_tbls[val] then - -- tbl_str[#tbl_str + 1] = tostring(val) .. ' already defined: ' .. tableshow_tbls[val] .. ',\n' - -- else - -- tableshow_tbls[val] = loc .. '[' .. basicSerialize(ind) .. ']' - -- tbl_str[#tbl_str + 1] = tostring(val) .. ' ' - -- tbl_str[#tbl_str + 1] = tableShow(val, loc .. '[' .. basicSerialize(ind).. ']', indent .. ' ', tableshow_tbls) - -- tbl_str[#tbl_str + 1] = ',\n' - -- end - -- elseif type(val) == 'function' then - -- if debug and debug.getinfo then - -- local fcnname = tostring(val) - -- local info = debug.getinfo(val, "S") - -- if info.what == "C" then - -- tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', C function') .. ',\n' - -- else - -- if (string.sub(info.source, 1, 2) == [[./]]) then - -- tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')' .. info.source) ..',\n' - -- else - -- tbl_str[#tbl_str + 1] = string.format('%q', fcnname .. ', defined in (' .. info.linedefined .. '-' .. info.lastlinedefined .. ')') ..',\n' - -- end - -- end - -- else - -- tbl_str[#tbl_str + 1] = 'a function,\n' - -- end - -- else - -- tbl_str[#tbl_str + 1] = 'unable to serialize value type ' .. basicSerialize(type(val)) .. ' at index ' .. tostring(ind) - -- end - -- end - -- tbl_str[#tbl_str + 1] = indent .. '}' - -- return table.concat(tbl_str) - -- end --- end - - - - --- function F10CargoDrop(GroupId, Unitname) - -- local rootPath = missionCommands.addSubMenuForGroup(GroupId, "Cargo Drop") - -- missionCommands.addCommandForGroup(GroupId, "Drop direction", rootPath, CruiseMissilesMessage, {GroupId, Unitname}) - -- missionCommands.addCommandForGroup(GroupId, "Drop distance", rootPath, ForwardConvoy, nil) - -- local measurementsSetPath = missionCommands.addSubMenuForGroup(GroupId,"Set measurement units",rootPath) - -- missionCommands.addCommandForGroup(GroupId, "Set to Imperial (feet, knts)",measurementsSetPath,setMeasurements,{GroupId, "imperial"}) - -- missionCommands.addCommandForGroup(GroupId, "Set to Metric (meters, km/h)",measurementsSetPath,setMeasurements,{GroupId, "metric"}) --- end - --- function Calculate_Object_Speed(object) - -- return math.sqrt(object:getVelocity().x^2 + object:getVelocity().y^2 + object:getVelocity().z^2) * 3600 / 1852 -- knts --- end - --- function vecDotProduct(vec1, vec2) - -- return vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z --- end - --- function Calculate_Aircraft_ForwardVelocity(Drop_initiator) - -- return vecDotProduct(Drop_initiator:getPosition().x, Drop_initiator:getVelocity()) --- end - - - diff --git a/resources/plugins/herculescargo/plugin.json b/resources/plugins/herculescargo/plugin.json deleted file mode 100644 index e80a5af0d..000000000 --- a/resources/plugins/herculescargo/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "nameInUI": "Include C130 Cargo script (Anubis Hercules mod)", - "defaultValue": false, - "specificOptions": [], - "scriptsWorkOrders": [ - { - "file": "Hercules_Cargo.lua", - "mnemonic": "Hercules_Cargo" - } - ], - "configurationWorkOrders": [] -} \ No newline at end of file diff --git a/resources/plugins/lotatc/LotAtcExport-config.lua b/resources/plugins/lotatc/LotAtcExport-config.lua deleted file mode 100644 index f7b0d8769..000000000 --- a/resources/plugins/lotatc/LotAtcExport-config.lua +++ /dev/null @@ -1,58 +0,0 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------- --- configuration file for the LotATC Export script --- --- This configuration is tailored for a mission generated by DCS Liberation --- see https://github.com/dcs-liberation/dcs_liberation -------------------------------------------------------------------------------------------------------------------------------------------------------------- - --- LotATC Export plugin - configuration -logger:info("DCSLiberation|LotATC Export plugin - configuration") - -local function discoverLotAtcDrawingsPath() - -- establish a search pattern into the following modes - -- 1. Environment variable LOTATC_DRAWINGS_DIR, to support server exporting with auto load from LotATC - -- 2. DCS saved games folder as configured in DCS Liberation - - local drawingEnvDir = os.getenv("LOTATC_DRAWINGS_DIR") - if drawingEnvDir then - return drawingEnvDir - else - return lfs.writedir()..[[\Mods\services\LotAtc\userdb\drawings\]] - end -end - -if dcsLiberation then - logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation") - - local exportRedAA = true - local exportBlueAA = false - local exportSymbols = true - - -- retrieve specific options values - if dcsLiberation.plugins then - logger:info("DCSLiberation|LotATC Export plugin - configuration dcsLiberation.plugins") - - if dcsLiberation.plugins.lotatc then - logger:info("DCSLiberation|LotATC Export plugin - dcsLiberation.plugins.lotatcExport") - - exportRedAA = dcsLiberation.plugins.lotatc.exportRedAA - logger:info(string.format("DCSLiberation|LotATC Export plugin - exportRedAA = %s",tostring(exportRedAA))) - - exportBlueAA = dcsLiberation.plugins.lotatc.exportBlueAA - logger:info(string.format("DCSLiberation|LotATC Export plugin - exportBlueAA = %s",tostring(exportBlueAA))) - - exportBlueAA = dcsLiberation.plugins.lotatc.exportSymbols - logger:info(string.format("DCSLiberation|LotATC Export plugin - exportSymbols = %s",tostring(exportSymbols))) - end - end - - -- actual configuration code - if LotAtcExportConfig then - LotAtcExportConfig.exportRedAA = exportRedAA - LotAtcExportConfig.exportBlueAA = exportBlueAA - LotAtcExportConfig.exportSymbols = exportSymbols - LotAtcExportConfig.drawingBasePath = discoverLotAtcDrawingsPath() - - LotatcExport() - end -end diff --git a/resources/plugins/lotatc/LotAtcExport.lua b/resources/plugins/lotatc/LotAtcExport.lua deleted file mode 100644 index c47852437..000000000 --- a/resources/plugins/lotatc/LotAtcExport.lua +++ /dev/null @@ -1,253 +0,0 @@ ---[[ -Export script for LotATC drawings - -Allows to export certain DCS Liberation objects as predefined drawing in LotATC. - -This script runs at mission startup and generates a drawing JSON file to be imported -in LotATC. -]] - -LotAtcExportConfig = { - ["exportRedAA"] = false, - ["exportBlueAA"] = false, - ["exportSymbols"] = false, - ["exportVersion"] = "2.2.0", - ["drawingBasePath"] = nil, - ["redColor"] = "#7FE32000", - ["blueColor"] = "#7F0084FF" -} - -local function factionName(isFriend) - if isFriend then - return "BLUE" - else - return "RED" - end -end - -local function uuid() - local random = math.random - local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' - return string.gsub(template, '[xy]', function (c) - local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) - return string.format('%x', v) - end) -end - -local function ends_with(str, ending) - return ending == "" or str:sub(-#ending) == ending - end - -local function combine(path1, path2) - if not ends_with(path1, "\\") then - path1 = path1 .. "\\" - end - - return path1 .. path2 -end - -local function lotatcExport_get_aa_nato_name(unit, isFriend) - if not redIADS or not blueIADS then - return nil - end - - -- logger:info(string.format("DCSLiberation|LotATC Export plugin - try get NATO name for unit %s", unit.dcsGroupName)) - - local iads = redIADS - if isFriend then - iads = blueIADS - end - - local samSite = iads:getSAMSiteByGroupName(unit.dcsGroupName) - if samSite and samSite.natoName then - -- logger:info(string.format("DCSLiberation|LotATC Export plugin - NATO name is %s", samSite.natoName)) - return samSite.natoName - else - return nil - end -end - -local function lotatcExport_get_name(unit, isFriend) - local classification = "SAM" - - if string.find(unit.dcsGroupName, "|EWR|", 1, true) then - classification = "EWR" - elseif string.find(unit.dcsGroupName, "|AA", 1, true) then - classification = "AAA" - end - - local natoName = lotatcExport_get_aa_nato_name(unit, isFriend) - - local name = nil - if not natoName then - name = string.format("%s|%s", unit.name, classification) - else - name = string.format("%s|%s|%s", unit.name, classification, natoName) - end - - return name, classification -end - -local function lotatc_write_json(filename, json) - logger:info(string.format("DCSLiberation|LotATC Export plugin - writing %s", filename)) - - local function Write() - local fp = io.open(filename, 'w') - if fp then - fp:write(json) - fp:close() - end - end - - if pcall(Write) then - else - logger:error("Unable to write LotATC export file to %s", filename) - end -end - -local function lotatcExport_threat_circles_for_faction(faction, color, isFriend) - local drawings = {} - - for _,aa in pairs(faction) do - logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting threat circle for %s", aa.dcsGroupName)) - - local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY}) - - local name = lotatcExport_get_name(aa, isFriend) - - table.insert(drawings, - { - ["author"] = "DCSLiberation", - ["brushStyle"] = 1, - ["color"] = color, - ["colorBg"] = "#00000000", - ["id"] = string.format("{%s}", uuid()), - ["longitude"] = convLon, - ["latitude"] = convLat, - ["radius"] = tonumber(aa.range), - ["lineWidth"] = 2, - ["name"] = name, - ["shared"] = true, - ["timestamp"] = "", - ["type"] = "circle", - ["text"] = name, - ["font"] = { - ["color"] = color, - ["font"] = "Lato" - } - }) - end - - local lotatcData = { - ["name"] = "Threat Circles " .. factionName(isFriend), - ["enable"] = "true", - ["version"] = LotAtcExportConfig.exportVersion, - ["drawings"] = drawings - } - - local drawings_json = json:encode(lotatcData) - return drawings_json -end - -local function lotatcExport_symbols_for_faction(faction, color, isFriend) - local drawings = {} - - for _,aa in pairs(faction) do - logger:info(string.format("DCSLiberation|LotATC Export plugin - exporting AA symbol for %s", aa.dcsGroupName)) - - local convLat, convLon = coord.LOtoLL({x = aa.positionX, y = 0, z = aa.positionY}) - - local name = lotatcExport_get_name(aa, isFriend) - - local classification = "hostile" - if isFriend then - classification = "friend" - end - - local sub_dimension = "none" - - if string.find(aa.dcsGroupName, "|EWR|", 1, true) then - sub_dimension = "ew" - end - - table.insert(drawings, - { - ["author"] = "DCSLiberation", - ["brushStyle"] = 1, - ["classification"] = { - ["classification"] = classification, - ["dimension"] = "land_unit", - ["sub_dimension"] = sub_dimension - }, - ["color"] = color, - ["colorBg"] = "#33FF0000", - ["font"] = { - ["color"] = color, - ["font"] = "Lato" - }, - ["id"] = string.format("{%s}", uuid()), - ["longitude"] = convLon, - ["latitude"] = convLat, - ["lineWidth"] = 2, - ["name"] = name, - ["shared"] = true, - ["timestamp"] = "", - ["type"] = "symbol", - ["text"] = name - }) - end - - local lotatcData = { - ["name"] = "Threat Symbols " .. factionName(isFriend), - ["enable"] = "true", - ["version"] = LotAtcExportConfig.exportVersion, - ["drawings"] = drawings, - } - - local drawings_json = json:encode(lotatcData) - return drawings_json -end - -local function lotatc_export_faction(faction, color, factionPath, isFriend) - local exportBasePathFaction = combine(LotAtcExportConfig.drawingBasePath, factionPath) - lfs.mkdir(exportBasePathFaction) - - local exportFileName = combine(exportBasePathFaction, "threatZones.json") - local json = lotatcExport_threat_circles_for_faction(faction, color, isFriend) - lotatc_write_json(exportFileName, json) - - if LotAtcExportConfig.exportSymbols then - exportFileName = combine(exportBasePathFaction, "threatSymbols.json") - json = lotatcExport_symbols_for_faction(faction, color, isFriend); - lotatc_write_json(exportFileName, json) - end -end - -function LotatcExport() - - if not json then - local message = "Unable to export LotATC drawings, JSON library is not loaded!" - logger:error(message) - return - end - - if not LotAtcExportConfig.drawingBasePath then - local message = "No writable export path for LotATC drawings. Set environment variable LOTATC_DRAWINGS_DIR pointing to your export path." - logger:error(message) - return - end - - local message = "Export LotATC drawings to "..LotAtcExportConfig.drawingBasePath - logger:info(message) - - -- The RED AA is exported to the blue folder and vice versa. If a BLUE GCI connects he/she - -- wants to see the RED AA. - - if LotAtcExportConfig.exportRedAA then - lotatc_export_faction(dcsLiberation.RedAA, LotAtcExportConfig.redColor, [[blue\]], false) - end - - if LotAtcExportConfig.exportBlueAA then - lotatc_export_faction(dcsLiberation.BlueAA, LotAtcExportConfig.blueColor, [[red\]], true) - end -end diff --git a/resources/plugins/lotatc/plugin.json b/resources/plugins/lotatc/plugin.json deleted file mode 100644 index 13af401d7..000000000 --- a/resources/plugins/lotatc/plugin.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "nameInUI": "LotATC Export", - "defaultValue": false, - "specificOptions": [ - { - "nameInUI": "Export RED AA", - "mnemonic": "exportRedAA", - "defaultValue": true - }, - { - "nameInUI": "Export BLUE AA", - "mnemonic": "exportBlueAA", - "defaultValue": false - }, - { - "nameInUI": "Export AA Symbols", - "mnemonic": "exportSymbols", - "defaultValue": true - } - ], - "scriptsWorkOrders": [ - { - "file": "LotAtcExport.lua", - "mnemonic": "LotAtcExport-script" - } - ], - "configurationWorkOrders": [ - { - "file": "LotAtcExport-config.lua", - "mnemonic": "LotAtcExport-config" - } - ] -} \ No newline at end of file diff --git a/resources/plugins/plugins.json b/resources/plugins/plugins.json deleted file mode 100644 index 777a0d2c3..000000000 --- a/resources/plugins/plugins.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - "base", - "ctld", - "skynetiads", - "ewrs", - "herculescargo", - "splashdamage", - "lotatc" -] diff --git a/resources/plugins/skynetiads/LICENSE.md b/resources/plugins/skynetiads/LICENSE.md deleted file mode 100644 index 261eeb9e9..000000000 --- a/resources/plugins/skynetiads/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/resources/plugins/skynetiads/plugin.json b/resources/plugins/skynetiads/plugin.json deleted file mode 100644 index 61f2ebc19..000000000 --- a/resources/plugins/skynetiads/plugin.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "nameInUI": "Skynet IADS", - "defaultValue": true, - "specificOptions": [ - { - "nameInUI": "create IADS for RED coalition", - "mnemonic": "createRedIADS", - "defaultValue": true - }, - { - "nameInUI": "create IADS for BLUE coalition", - "mnemonic": "createBlueIADS", - "defaultValue": true - }, - { - "nameInUI": "Include RED IADS in radio menu", - "mnemonic": "includeRedInRadio", - "defaultValue": true - }, - { - "nameInUI": "Include BLUE IADS in radio menu", - "mnemonic": "includeBlueInRadio", - "defaultValue": true - }, - { - "nameInUI": "Generate debug information for RED IADS", - "mnemonic": "debugRED", - "defaultValue": false - }, - { - "nameInUI": "Generate debug information for BLUE IADS", - "mnemonic": "debugBLUE", - "defaultValue": false - } - ], - "scriptsWorkOrders": [ - { - "file": "skynet-iads-compiled.lua", - "mnemonic": "skynetiads-script" - } - ], - "configurationWorkOrders": [ - { - "file": "skynetiads-config.lua", - "mnemonic": "skynetiads-config" - } - ] -} \ No newline at end of file diff --git a/resources/plugins/skynetiads/skynet-iads-compiled.lua b/resources/plugins/skynetiads/skynet-iads-compiled.lua deleted file mode 100644 index de42d2523..000000000 --- a/resources/plugins/skynetiads/skynet-iads-compiled.lua +++ /dev/null @@ -1,3850 +0,0 @@ -env.info("--- SKYNET VERSION: 3.0.1 | BUILD TIME: 06.11.2022 1728Z ---") -do ---this file contains the required units per sam type -samTypesDB = { - ['S-200'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['RLS_19J6'] = { - ['name'] = { - ['NATO'] = 'Tin Shield', - }, - }, - ['p-19 s-125 sr'] = { - ['name'] = { - ['NATO'] = 'Flat Face', - }, - }, - }, - ['EWR P-37 BAR LOCK'] = { - ['Name'] = { - ['NATO'] = "Bar lock", - }, - }, - ['trackingRadar'] = { - ['RPC_5N62V'] = { - }, - }, - ['launchers'] = { - ['S-200_Launcher'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-5 Gammon', - }, - ['harm_detection_chance'] = 60 - }, - ['S-300'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300PS 40B6MD sr'] = { - ['name'] = { - ['NATO'] = 'Clam Shell', - }, - }, - ['S-300PS 64H6E sr'] = { - ['name'] = { - ['NATO'] = 'Big Bird', - }, - }, - }, - ['trackingRadar'] = { - ['S-300PS 40B6M tr'] = { - }, - }, - ['launchers'] = { - ['S-300PS 5P85D ln'] = { - }, - ['S-300PS 5P85C ln'] = { - }, - }, - ['misc'] = { - ['S-300PS 54K6 cp'] = { - ['required'] = true, - }, - }, - ['name'] = { - ['NATO'] = 'SA-10 Grumble', - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true - }, - ['Buk'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['SA-11 Buk SR 9S18M1'] = { - ['name'] = { - ['NATO'] = 'Snow Drift', - }, - }, - }, - ['launchers'] = { - ['SA-11 Buk LN 9A310M1'] = { - }, - }, - ['misc'] = { - ['SA-11 Buk CC 9S470M1'] = { - ['required'] = true, - }, - }, - ['name'] = { - ['NATO'] = 'SA-11 Gadfly', - }, - ['harm_detection_chance'] = 70 - }, - ['S-125'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['p-19 s-125 sr'] = { - ['name'] = { - ['NATO'] = 'Flat Face', - }, - }, - }, - ['trackingRadar'] = { - ['snr s-125 tr'] = { - }, - }, - ['launchers'] = { - ['5p73 s-125 ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-3 Goa', - }, - ['harm_detection_chance'] = 30 - }, - ['S-75'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['p-19 s-125 sr'] = { - ['name'] = { - ['NATO'] = 'Flat Face', - }, - }, - }, - ['trackingRadar'] = { - ['SNR_75V'] = { - }, - }, - ['launchers'] = { - ['S_75M_Volhov'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-2 Guideline', - }, - ['harm_detection_chance'] = 30 - }, - ['Kub'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['Kub 1S91 str'] = { - ['name'] = { - ['NATO'] = 'Straight Flush', - }, - }, - }, - ['launchers'] = { - ['Kub 2P25 ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-6 Gainful', - }, - ['harm_detection_chance'] = 40 - }, - ['Patriot'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['Patriot str'] = { - ['name'] = { - ['NATO'] = 'Patriot str', - }, - }, - }, - ['launchers'] = { - ['Patriot ln'] = { - }, - }, - ['misc'] = { - ['Patriot cp'] = { - ['required'] = false, - }, - ['Patriot EPP'] = { - ['required'] = false, - }, - ['Patriot ECS'] = { - ['required'] = true, - }, - ['Patriot AMG'] = { - ['required'] = false, - }, - }, - ['name'] = { - ['NATO'] = 'Patriot', - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true - }, - ['Hawk'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['Hawk sr'] = { - ['name'] = { - ['NATO'] = 'Hawk str', - }, - }, - }, - ['trackingRadar'] = { - ['Hawk tr'] = { - }, - }, - ['launchers'] = { - ['Hawk ln'] = { - }, - }, - - ['name'] = { - ['NATO'] = 'Hawk', - }, - ['harm_detection_chance'] = 40 - - }, - ['Roland ADS'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Roland ADS'] = { - }, - }, - ['launchers'] = { - ['Roland ADS'] = { - }, - }, - - ['name'] = { - ['NATO'] = 'Roland ADS', - }, - ['harm_detection_chance'] = 60 - }, - ['NASAMS'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['NASAMS_Radar_MPQ64F1'] = { - }, - }, - ['launchers'] = { - ['NASAMS_LN_B'] = { - }, - ['NASAMS_LN_C'] = { - }, - }, - - ['name'] = { - ['NATO'] = 'NASAMS', - }, - ['misc'] = { - ['NASAMS_Command_Post'] = { - ['required'] = false, - }, - }, - ['can_engage_harm'] = true, - ['harm_detection_chance'] = 90 - }, - ['2S6 Tunguska'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['2S6 Tunguska'] = { - }, - }, - ['launchers'] = { - ['2S6 Tunguska'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-19 Grison', - }, - }, - ['Osa'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Osa 9A33 ln'] = { - }, - }, - ['launchers'] = { - ['Osa 9A33 ln'] = { - - }, - }, - ['name'] = { - ['NATO'] = 'SA-8 Gecko', - }, - ['harm_detection_chance'] = 20 - }, - ['Strela-10M3'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Strela-10M3'] = { - ['trackingRadar'] = true, - }, - }, - ['launchers'] = { - ['Strela-10M3'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-13 Gopher', - }, - }, - ['Strela-1 9P31'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Strela-1 9P31'] = { - }, - }, - ['launchers'] = { - ['Strela-1 9P31'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-9 Gaskin', - }, - ['harm_detection_chance'] = 20 - }, - ['Tor'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Tor 9A331'] = { - }, - }, - ['launchers'] = { - ['Tor 9A331'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-15 Gauntlet', - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true - - }, - ['Gepard'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['Gepard'] = { - }, - }, - ['launchers'] = { - ['Gepard'] = { - }, - }, - ['name'] = { - ['NATO'] = 'Gepard', - }, - ['harm_detection_chance'] = 10 - }, - ['Rapier'] = { - ['searchRadar'] = { - ['rapier_fsa_blindfire_radar'] = { - }, - }, - ['launchers'] = { - ['rapier_fsa_launcher'] = { - ['trackingRadar'] = true, - }, - }, - ['misc'] = { - ['rapier_fsa_optical_tracker_unit'] = { - ['required'] = true, - }, - }, - ['name'] = { - ['NATO'] = 'Rapier', - }, - ['harm_detection_chance'] = 10 - }, - ['ZSU-23-4 Shilka'] = { - ['type'] = 'single', - ['searchRadar'] = { - ['ZSU-23-4 Shilka'] = { - }, - }, - ['launchers'] = { - ['ZSU-23-4 Shilka'] = { - }, - }, - ['name'] = { - ['NATO'] = 'Zues', - }, - ['harm_detection_chance'] = 10 - }, - ['HQ-7'] = { - ['searchRadar'] = { - ['HQ-7_STR_SP'] = { - ['name'] = { - ['NATO'] = 'CSA-4', - }, - }, - }, - ['launchers'] = { - ['HQ-7_LN_SP'] = { - }, - }, - ['name'] = { - ['NATO'] = 'CSA-4', - }, - ['harm_detection_chance'] = 30 - }, ---- Start of EW radars: - ['1L13 EWR'] = { - ['type'] = 'ewr', - ['searchRadar'] = { - ['1L13 EWR'] = { - ['name'] = { - ['NATO'] = 'Box Spring', - }, - }, - }, - ['harm_detection_chance'] = 60 - }, - ['55G6 EWR'] = { - ['type'] = 'ewr', - ['searchRadar'] = { - ['55G6 EWR'] = { - ['name'] = { - ['NATO'] = 'Tall Rack', - }, - }, - }, - ['harm_detection_chance'] = 60 - }, - ['Dog Ear'] = { - ['type'] = 'ewr', - ['searchRadar'] = { - ['Dog Ear radar'] = { - ['name'] = { - ['NATO'] = 'Dog Ear', - }, - }, - }, - ['harm_detection_chance'] = 20 - }, - ['Roland Radar'] = { - ['type'] = 'ewr', - ['searchRadar'] = { - ['Roland Radar'] = { - ['name'] = { - ['NATO'] = 'Roland EWR', - }, - }, - }, - - ['harm_detection_chance'] = 60 - }, -} -end -do --- this file contains the definitions for the HightDigitSAMSs: https://github.com/Auranis/HighDigitSAMs - ---EW radars used in multiple SAM systems: - -s300PMU164N6Esr = { - ['name'] = { - ['NATO'] = 'Big Bird', - }, -} - -s300PMU140B6MDsr = { - ['name'] = { - ['NATO'] = 'Clam Shell', - }, -} - ---[[ units in SA-10 group Gargoyle: -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 54K6 cp -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 5P85CE ln -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 5P85DE ln -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 40B6MD sr -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 64N6E sr -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 40B6M tr -2020-12-10 18:27:27.050 INFO SCRIPTING: S-300PMU1 30N6E tr ---]] -samTypesDB['S-300PMU1'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300PMU1 40B6MD sr'] = s300PMU140B6MDsr, - ['S-300PMU1 64N6E sr'] = s300PMU164N6Esr, - - ['S-300PS 40B6MD sr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - ['S-300PS 64H6E sr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - }, - ['trackingRadar'] = { - ['S-300PMU1 40B6M tr'] = { - ['name'] = { - ['NATO'] = 'Grave Stone', - }, - }, - ['S-300PMU1 30N6E tr'] = { - ['name'] = { - ['NATO'] = 'Flap Lid', - }, - - }, - ['S-300PS 40B6M tr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - }, - ['misc'] = { - ['S-300PMU1 54K6 cp'] = { - ['required'] = true, - }, - }, - ['launchers'] = { - ['S-300PMU1 5P85CE ln'] = { - }, - ['S-300PMU1 5P85DE ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-20A Gargoyle' - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true -} - ---[[ Units in the SA-23 Group: -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9A82ME ln -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9A83ME ln -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9S15M2 sr -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9S19M2 sr -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9S32ME tr -2020-12-11 16:40:52.072 INFO SCRIPTING: S-300VM 9S457ME cp - -]]-- -samTypesDB['S-300VM'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300VM 9S15M2 sr'] = { - ['name'] = { - ['NATO'] = 'Bill Board-C', - }, - }, - ['S-300VM 9S19M2 sr'] = { - ['name'] = { - ['NATO'] = 'High Screen-B', - }, - }, - }, - ['trackingRadar'] = { - ['S-300VM 9S32ME tr'] = { - }, - }, - ['misc'] = { - ['S-300VM 9S457ME cp'] = { - ['required'] = true, - }, - }, - ['launchers'] = { - ['S-300VM 9A82ME ln'] = { - }, - ['S-300VM 9A83ME ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-23 Antey-2500' - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true -} - ---[[ Units in the SA-10B Group: -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS SA-10B 40B6MD MAST sr -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS SA-10B 54K6 cp -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS 5P85SE_mod ln -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS 5P85SU_mod ln -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS 64H6E TRAILER sr -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS 30N6 TRAILER tr -2021-01-01 20:39:14.413 INFO SCRIPTING: S-300PS SA-10B 40B6M MAST tr ---]] -samTypesDB['S-300PS'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300PS SA-10B 40B6MD MAST sr'] = { - ['name'] = { - ['NATO'] = 'Clam Shell', - }, - }, - ['S-300PS 64H6E TRAILER sr'] = { - }, - }, - ['trackingRadar'] = { - ['S-300PS 30N6 TRAILER tr'] = { - }, - ['S-300PS SA-10B 40B6M MAST tr'] = { - }, - ['S-300PS 40B6M tr'] = { - }, - ['S-300PMU1 40B6M tr'] = { - }, - ['S-300PMU1 30N6E tr'] = { - }, - }, - ['misc'] = { - ['S-300PS SA-10B 54K6 cp'] = { - ['required'] = true, - }, - }, - ['launchers'] = { - ['S-300PS 5P85SE_mod ln'] = { - }, - ['S-300PS 5P85SU_mod ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-10B Grumble' - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true -} - ---[[ Extra launchers for the in game SA-10C and HighDigitSAMs SA-10B, SA-20B -2021-01-01 21:04:19.908 INFO SCRIPTING: S-300PS 5P85DE ln -2021-01-01 21:04:19.908 INFO SCRIPTING: S-300PS 5P85CE ln ---]] - -local s300launchers = samTypesDB['S-300']['launchers'] -s300launchers['S-300PS 5P85DE ln'] = {} -s300launchers['S-300PS 5P85CE ln'] = {} - -local s300launchers = samTypesDB['S-300PS']['launchers'] -s300launchers['S-300PS 5P85DE ln'] = {} -s300launchers['S-300PS 5P85CE ln'] = {} - -local s300launchers = samTypesDB['S-300PMU1']['launchers'] -s300launchers['S-300PS 5P85DE ln'] = {} -s300launchers['S-300PS 5P85CE ln'] = {} - ---[[ -New launcher for the SA-11 complex, will identify as SA-17 -SA-17 Buk M1-2 LN 9A310M1-2 - --]] -samTypesDB['Buk-M2'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['SA-11 Buk SR 9S18M1'] = { - ['name'] = { - ['NATO'] = 'Snow Drift', - }, - }, - }, - ['launchers'] = { - ['SA-17 Buk M1-2 LN 9A310M1-2'] = { - }, - }, - ['misc'] = { - ['SA-11 Buk CC 9S470M1'] = { - ['required'] = true, - }, - }, - ['name'] = { - ['NATO'] = 'SA-17 Grizzly', - }, - ['harm_detection_chance'] = 90 -} - ---[[ -New launcher for the SA-2 complex: S_75M_Volhov_V759 ---]] -local s75launchers = samTypesDB['S-75']['launchers'] -s75launchers['S_75M_Volhov_V759'] = {} - ---[[ -New launcher for the SA-3 complex: ---]] -local s125launchers = samTypesDB['S-125']['launchers'] -s125launchers['5p73 V-601P ln'] = {} - ---[[ -New launcher for the SA-2 complex: HQ_2_Guideline_LN ---]] -local s125launchers = samTypesDB['S-75']['launchers'] -s125launchers['HQ_2_Guideline_LN'] = {} - ---[[ -SA-12 Gladiator / Giant: -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9S15 sr -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9S19 sr -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9S32 tr -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9S457 cp -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9A83 ln -2021-03-19 21:24:22.620 INFO SCRIPTING: S-300V 9A82 ln ---]] -samTypesDB['S-300V'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300V 9S15 sr'] = { - ['name'] = { - ['NATO'] = 'Bill Board', - }, - }, - ['S-300V 9S19 sr'] = { - ['name'] = { - ['NATO'] = 'High Screen', - }, - }, - }, - ['trackingRadar'] = { - ['S-300V 9S32 tr'] = { - ['NATO'] = 'Grill Pan', - }, - }, - ['misc'] = { - ['S-300V 9S457 cp'] = { - ['required'] = true, - }, - }, - ['launchers'] = { - ['S-300V 9A83 ln'] = { - }, - ['S-300V 9A82 ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-12 Gladiator/Giant' - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true -} - ---[[ -SA-20B Gargoyle B: - -2021-03-25 19:15:02.135 INFO SCRIPTING: S-300PMU2 64H6E2 sr -2021-03-25 19:15:02.135 INFO SCRIPTING: S-300PMU2 92H6E tr -2021-03-25 19:15:02.135 INFO SCRIPTING: S-300PMU2 5P85SE2 ln -2021-03-25 19:15:02.135 INFO SCRIPTING: S-300PMU2 54K6E2 cp ---]] - -samTypesDB['S-300PMU2'] = { - ['type'] = 'complex', - ['searchRadar'] = { - ['S-300PMU2 64H6E2 sr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - ['S-300PMU1 40B6MD sr'] = s300PMU140B6MDsr, - ['S-300PMU1 64N6E sr'] = s300PMU164N6Esr, - - ['S-300PS 40B6MD sr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - ['S-300PS 64H6E sr'] = { - ['name'] = { - ['NATO'] = '', - }, - }, - }, - ['trackingRadar'] = { - ['S-300PMU2 92H6E tr'] = { - }, - ['S-300PS 40B6M tr'] = { - }, - ['S-300PMU1 40B6M tr'] = { - }, - ['S-300PMU1 30N6E tr'] = { - }, - }, - ['misc'] = { - ['S-300PMU2 54K6E2 cp'] = { - ['required'] = true, - }, - }, - ['launchers'] = { - ['S-300PMU2 5P85SE2 ln'] = { - }, - }, - ['name'] = { - ['NATO'] = 'SA-20B Gargoyle B' - }, - ['harm_detection_chance'] = 90, - ['can_engage_harm'] = true -} - ---[[ - ---]] -end - - - -do - -SkynetIADSLogger = {} -SkynetIADSLogger.__index = SkynetIADSLogger - -function SkynetIADSLogger:create(iads) - local logger = {} - setmetatable(logger, SkynetIADSLogger) - logger.debugOutput = {} - logger.debugOutput.IADSStatus = false - logger.debugOutput.samWentDark = false - logger.debugOutput.contacts = false - logger.debugOutput.radarWentLive = false - logger.debugOutput.jammerProbability = false - logger.debugOutput.addedEWRadar = false - logger.debugOutput.addedSAMSite = false - logger.debugOutput.warnings = true - logger.debugOutput.harmDefence = false - logger.debugOutput.samSiteStatusEnvOutput = false - logger.debugOutput.earlyWarningRadarStatusEnvOutput = false - logger.debugOutput.commandCenterStatusEnvOutput = false - logger.iads = iads - return logger -end - -function SkynetIADSLogger:getDebugSettings() - return self.debugOutput -end - -function SkynetIADSLogger:printOutput(output, typeWarning) - if typeWarning == true and self:getDebugSettings().warnings or typeWarning == nil then - if typeWarning == true then - output = "WARNING: "..output - end - trigger.action.outText(output, 4) - end -end - -function SkynetIADSLogger:printOutputToLog(output) - env.info("SKYNET: "..output, 4) -end - -function SkynetIADSLogger:printEarlyWarningRadarStatus() - local ewRadars = self.iads:getEarlyWarningRadars() - self:printOutputToLog("------------------------------------------ EW RADAR STATUS: "..self.iads:getCoalitionString().." -------------------------------") - for i = 1, #ewRadars do - local ewRadar = ewRadars[i] - local numConnectionNodes = #ewRadar:getConnectionNodes() - local numPowerSources = #ewRadar:getPowerSources() - local isActive = ewRadar:isActive() - local connectionNodes = ewRadar:getConnectionNodes() - local firstRadar = nil - local radars = ewRadar:getRadars() - - --get the first existing radar to prevent issues in calculating the distance later on: - for i = 1, #radars do - if radars[i]:isExist() then - firstRadar = radars[i] - break - end - - end - local numDamagedConnectionNodes = 0 - - - for j = 1, #connectionNodes do - local connectionNode = connectionNodes[j] - if connectionNode:isExist() == false then - numDamagedConnectionNodes = numDamagedConnectionNodes + 1 - end - end - local intactConnectionNodes = numConnectionNodes - numDamagedConnectionNodes - - local powerSources = ewRadar:getPowerSources() - local numDamagedPowerSources = 0 - for j = 1, #powerSources do - local powerSource = powerSources[j] - if powerSource:isExist() == false then - numDamagedPowerSources = numDamagedPowerSources + 1 - end - end - local intactPowerSources = numPowerSources - numDamagedPowerSources - - local detectedTargets = ewRadar:getDetectedTargets() - local samSitesInCoveredArea = ewRadar:getChildRadars() - - local unitName = "DESTROYED" - - if ewRadar:getDCSRepresentation():isExist() then - unitName = ewRadar:getDCSName() - end - - self:printOutputToLog("UNIT: "..unitName.." | TYPE: "..ewRadar:getNatoName()) - self:printOutputToLog("ACTIVE: "..tostring(isActive).."| DETECTED TARGETS: "..#detectedTargets.." | DEFENDING HARM: "..tostring(ewRadar:isDefendingHARM())) - if numConnectionNodes > 0 then - self:printOutputToLog("CONNECTION NODES: "..numConnectionNodes.." | DAMAGED: "..numDamagedConnectionNodes.." | INTACT: "..intactConnectionNodes) - else - self:printOutputToLog("NO CONNECTION NODES SET") - end - if numPowerSources > 0 then - self:printOutputToLog("POWER SOURCES : "..numPowerSources.." | DAMAGED:"..numDamagedPowerSources.." | INTACT: "..intactPowerSources) - else - self:printOutputToLog("NO POWER SOURCES SET") - end - - self:printOutputToLog("SAM SITES IN COVERED AREA: "..#samSitesInCoveredArea) - for j = 1, #samSitesInCoveredArea do - local samSiteCovered = samSitesInCoveredArea[j] - self:printOutputToLog(samSiteCovered:getDCSName()) - end - - for j = 1, #detectedTargets do - local contact = detectedTargets[j] - if firstRadar ~= nil and firstRadar:isExist() then - local distance = mist.utils.round(mist.utils.metersToNM(ewRadar:getDistanceInMetersToContact(firstRadar:getDCSRepresentation(), contact:getPosition().p)), 2) - self:printOutputToLog("CONTACT: "..contact:getName().." | TYPE: "..contact:getTypeName().." | DISTANCE NM: "..distance) - end - end - - self:printOutputToLog("---------------------------------------------------") - - end - -end - -function SkynetIADSLogger:getMetaInfo(abstractElementSupport) - local info = {} - info.numSources = #abstractElementSupport - info.numDamagedSources = 0 - info.numIntactSources = 0 - for j = 1, #abstractElementSupport do - local source = abstractElementSupport[j] - if source:isExist() == false then - info.numDamagedSources = info.numDamagedSources + 1 - end - end - info.numIntactSources = info.numSources - info.numDamagedSources - return info -end - -function SkynetIADSLogger:printSAMSiteStatus() - local samSites = self.iads:getSAMSites() - - self:printOutputToLog("------------------------------------------ SAM STATUS: "..self.iads:getCoalitionString().." -------------------------------") - for i = 1, #samSites do - local samSite = samSites[i] - local numConnectionNodes = #samSite:getConnectionNodes() - local numPowerSources = #samSite:getPowerSources() - local isAutonomous = samSite:getAutonomousState() - local isActive = samSite:isActive() - - local connectionNodes = samSite:getConnectionNodes() - local firstRadar = samSite:getRadars()[1] - local numDamagedConnectionNodes = 0 - for j = 1, #connectionNodes do - local connectionNode = connectionNodes[j] - if connectionNode:isExist() == false then - numDamagedConnectionNodes = numDamagedConnectionNodes + 1 - end - end - local intactConnectionNodes = numConnectionNodes - numDamagedConnectionNodes - - local powerSources = samSite:getPowerSources() - local numDamagedPowerSources = 0 - for j = 1, #powerSources do - local powerSource = powerSources[j] - if powerSource:isExist() == false then - numDamagedPowerSources = numDamagedPowerSources + 1 - end - end - local intactPowerSources = numPowerSources - numDamagedPowerSources - - local detectedTargets = samSite:getDetectedTargets() - - local samSitesInCoveredArea = samSite:getChildRadars() - - local engageAirWeapons = samSite:getCanEngageAirWeapons() - - local engageHARMS = samSite:getCanEngageHARM() - - local hasAmmo = samSite:hasRemainingAmmo() - - self:printOutputToLog("GROUP: "..samSite:getDCSName().." | TYPE: "..samSite:getNatoName()) - self:printOutputToLog("ACTIVE: "..tostring(isActive).." | AUTONOMOUS: "..tostring(isAutonomous).." | IS ACTING AS EW: "..tostring(samSite:getActAsEW()).." | CAN ENGAGE AIR WEAPONS : "..tostring(engageAirWeapons).." | CAN ENGAGE HARMS : "..tostring(engageHARMS).." | HAS AMMO: "..tostring(hasAmmo).." | DETECTED TARGETS: "..#detectedTargets.." | DEFENDING HARM: "..tostring(samSite:isDefendingHARM()).." | MISSILES IN FLIGHT: "..tostring(samSite:getNumberOfMissilesInFlight())) - - if numConnectionNodes > 0 then - self:printOutputToLog("CONNECTION NODES: "..numConnectionNodes.." | DAMAGED: "..numDamagedConnectionNodes.." | INTACT: "..intactConnectionNodes) - else - self:printOutputToLog("NO CONNECTION NODES SET") - end - if numPowerSources > 0 then - self:printOutputToLog("POWER SOURCES : "..numPowerSources.." | DAMAGED:"..numDamagedPowerSources.." | INTACT: "..intactPowerSources) - else - self:printOutputToLog("NO POWER SOURCES SET") - end - - self:printOutputToLog("SAM SITES IN COVERED AREA: "..#samSitesInCoveredArea) - for j = 1, #samSitesInCoveredArea do - local samSiteCovered = samSitesInCoveredArea[j] - self:printOutputToLog(samSiteCovered:getDCSName()) - end - - for j = 1, #detectedTargets do - local contact = detectedTargets[j] - if firstRadar ~= nil and firstRadar:isExist() then - local distance = mist.utils.round(mist.utils.metersToNM(samSite:getDistanceInMetersToContact(firstRadar:getDCSRepresentation(), contact:getPosition().p)), 2) - self:printOutputToLog("CONTACT: "..contact:getName().." | TYPE: "..contact:getTypeName().." | DISTANCE NM: "..distance) - end - end - - self:printOutputToLog("---------------------------------------------------") - end -end - -function SkynetIADSLogger:printCommandCenterStatus() - local commandCenters = self.iads:getCommandCenters() - self:printOutputToLog("------------------------------------------ COMMAND CENTER STATUS: "..self.iads:getCoalitionString().." -------------------------------") - - for i = 1, #commandCenters do - local commandCenter = commandCenters[i] - local numConnectionNodes = #commandCenter:getConnectionNodes() - local powerSourceInfo = self:getMetaInfo(commandCenter:getPowerSources()) - local connectionNodeInfo = self:getMetaInfo(commandCenter:getConnectionNodes()) - self:printOutputToLog("GROUP: "..commandCenter:getDCSName().." | TYPE: "..commandCenter:getNatoName()) - if connectionNodeInfo.numSources > 0 then - self:printOutputToLog("CONNECTION NODES: "..connectionNodeInfo.numSources.." | DAMAGED: "..connectionNodeInfo.numDamagedSources.." | INTACT: "..connectionNodeInfo.numIntactSources) - else - self:printOutputToLog("NO CONNECTION NODES SET") - end - if powerSourceInfo.numSources > 0 then - self:printOutputToLog("POWER SOURCES : "..powerSourceInfo.numSources.." | DAMAGED: "..powerSourceInfo.numDamagedSources.." | INTACT: "..powerSourceInfo.numIntactSources) - else - self:printOutputToLog("NO POWER SOURCES SET") - end - self:printOutputToLog("---------------------------------------------------") - end -end - -function SkynetIADSLogger:printSystemStatus() - - if self:getDebugSettings().IADSStatus or self:getDebugSettings().contacts then - local coalitionStr = self.iads:getCoalitionString() - self:printOutput("---- IADS: "..coalitionStr.." ------") - end - - if self:getDebugSettings().IADSStatus then - - local commandCenters = self.iads:getCommandCenters() - local numComCenters = #commandCenters - local numDestroyedComCenters = 0 - local numComCentersNoPower = 0 - local numComCentersNoConnectionNode = 0 - local numIntactComCenters = 0 - for i = 1, #commandCenters do - local commandCenter = commandCenters[i] - if commandCenter:hasWorkingPowerSource() == false then - numComCentersNoPower = numComCentersNoPower + 1 - end - if commandCenter:hasActiveConnectionNode() == false then - numComCentersNoConnectionNode = numComCentersNoConnectionNode + 1 - end - if commandCenter:isDestroyed() == false then - numIntactComCenters = numIntactComCenters + 1 - end - end - - numDestroyedComCenters = numComCenters - numIntactComCenters - - - self:printOutput("COMMAND CENTERS: "..numComCenters.." | Destroyed: "..numDestroyedComCenters.." | NoPowr: "..numComCentersNoPower.." | NoCon: "..numComCentersNoConnectionNode) - - local ewNoPower = 0 - local earlyWarningRadars = self.iads:getEarlyWarningRadars() - local ewTotal = #earlyWarningRadars - local ewNoConnectionNode = 0 - local ewActive = 0 - local ewRadarsInactive = 0 - - for i = 1, #earlyWarningRadars do - local ewRadar = earlyWarningRadars[i] - if ewRadar:hasWorkingPowerSource() == false then - ewNoPower = ewNoPower + 1 - end - if ewRadar:hasActiveConnectionNode() == false then - ewNoConnectionNode = ewNoConnectionNode + 1 - end - if ewRadar:isActive() then - ewActive = ewActive + 1 - end - end - - ewRadarsInactive = ewTotal - ewActive - local numEWRadarsDestroyed = #self.iads:getDestroyedEarlyWarningRadars() - self:printOutput("EW: "..ewTotal.." | On: "..ewActive.." | Off: "..ewRadarsInactive.." | Destroyed: "..numEWRadarsDestroyed.." | NoPowr: "..ewNoPower.." | NoCon: "..ewNoConnectionNode) - - local samSitesInactive = 0 - local samSitesActive = 0 - local samSites = self.iads:getSAMSites() - local samSitesTotal = #samSites - local samSitesNoPower = 0 - local samSitesNoConnectionNode = 0 - local samSitesOutOfAmmo = 0 - local samSiteAutonomous = 0 - local samSiteRadarDestroyed = 0 - for i = 1, #samSites do - local samSite = samSites[i] - if samSite:hasWorkingPowerSource() == false then - samSitesNoPower = samSitesNoPower + 1 - end - if samSite:hasActiveConnectionNode() == false then - samSitesNoConnectionNode = samSitesNoConnectionNode + 1 - end - if samSite:isActive() then - samSitesActive = samSitesActive + 1 - end - if samSite:hasRemainingAmmo() == false then - samSitesOutOfAmmo = samSitesOutOfAmmo + 1 - end - if samSite:getAutonomousState() == true then - samSiteAutonomous = samSiteAutonomous + 1 - end - if samSite:hasWorkingRadar() == false then - samSiteRadarDestroyed = samSiteRadarDestroyed + 1 - end - end - - samSitesInactive = samSitesTotal - samSitesActive - self:printOutput("SAM: "..samSitesTotal.." | On: "..samSitesActive.." | Off: "..samSitesInactive.." | Autonm: "..samSiteAutonomous.." | Raddest: "..samSiteRadarDestroyed.." | NoPowr: "..samSitesNoPower.." | NoCon: "..samSitesNoConnectionNode.." | NoAmmo: "..samSitesOutOfAmmo) - end - - if self:getDebugSettings().contacts then - local contacts = self.iads:getContacts() - if contacts then - for i = 1, #contacts do - local contact = contacts[i] - self:printOutput("CONTACT: "..contact:getName().." | TYPE: "..contact:getTypeName().." | GS: "..tostring(contact:getGroundSpeedInKnots()).." | LAST SEEN: "..contact:getAge()) - end - end - end - - if self:getDebugSettings().commandCenterStatusEnvOutput then - self:printCommandCenterStatus() - end - - if self:getDebugSettings().earlyWarningRadarStatusEnvOutput then - self:printEarlyWarningRadarStatus() - end - - if self:getDebugSettings().samSiteStatusEnvOutput then - self:printSAMSiteStatus() - end - -end - -end -do - -SkynetIADS = {} -SkynetIADS.__index = SkynetIADS - -SkynetIADS.database = samTypesDB - -function SkynetIADS:create(name) - local iads = {} - setmetatable(iads, SkynetIADS) - iads.radioMenu = nil - iads.earlyWarningRadars = {} - iads.samSites = {} - iads.commandCenters = {} - iads.ewRadarScanMistTaskID = nil - iads.coalition = nil - iads.contacts = {} - iads.maxTargetAge = 32 - iads.name = name - iads.harmDetection = SkynetIADSHARMDetection:create(iads) - iads.logger = SkynetIADSLogger:create(iads) - if iads.name == nil then - iads.name = "" - end - iads.contactUpdateInterval = 5 - return iads -end - -function SkynetIADS:setUpdateInterval(interval) - self.contactUpdateInterval = interval -end - -function SkynetIADS:setCoalition(item) - if item then - local coalitionID = item:getCoalition() - if self.coalitionID == nil then - self.coalitionID = coalitionID - end - if self.coalitionID ~= coalitionID then - self:printOutputToLog("element: "..item:getName().." has a different coalition than the IADS", true) - end - end -end - -function SkynetIADS:addJammer(jammer) - table.insert(self.jammers, jammer) -end - -function SkynetIADS:getCoalition() - return self.coalitionID -end - -function SkynetIADS:getDestroyedEarlyWarningRadars() - local destroyedSites = {} - for i = 1, #self.earlyWarningRadars do - local ewSite = self.earlyWarningRadars[i] - if ewSite:isDestroyed() then - table.insert(destroyedSites, ewSite) - end - end - return destroyedSites -end - -function SkynetIADS:getUsableAbstractRadarElemtentsOfTable(abstractRadarTable) - local usable = {} - for i = 1, #abstractRadarTable do - local abstractRadarElement = abstractRadarTable[i] - if abstractRadarElement:hasActiveConnectionNode() and abstractRadarElement:hasWorkingPowerSource() and abstractRadarElement:isDestroyed() == false then - table.insert(usable, abstractRadarElement) - end - end - return usable -end - -function SkynetIADS:getUsableEarlyWarningRadars() - return self:getUsableAbstractRadarElemtentsOfTable(self.earlyWarningRadars) -end - -function SkynetIADS:createTableDelegator(units) - local sites = SkynetIADSTableDelegator:create() - for i = 1, #units do - local site = units[i] - table.insert(sites, site) - end - return sites -end - -function SkynetIADS:addEarlyWarningRadarsByPrefix(prefix) - self:deactivateEarlyWarningRadars() - self.earlyWarningRadars = {} - for unitName, unit in pairs(mist.DBs.unitsByName) do - local pos = self:findSubString(unitName, prefix) - --somehow the MIST unit db contains StaticObject, we check to see we only add Units - local unit = Unit.getByName(unitName) - if pos and pos == 1 and unit then - self:addEarlyWarningRadar(unitName) - end - end - return self:createTableDelegator(self.earlyWarningRadars) -end - -function SkynetIADS:addEarlyWarningRadar(earlyWarningRadarUnitName) - local earlyWarningRadarUnit = Unit.getByName(earlyWarningRadarUnitName) - if earlyWarningRadarUnit == nil then - self:printOutputToLog("you have added an EW Radar that does not exist, check name of Unit in Setup and Mission editor: "..earlyWarningRadarUnitName, true) - return - end - self:setCoalition(earlyWarningRadarUnit) - local ewRadar = nil - local category = earlyWarningRadarUnit:getDesc().category - if category == Unit.Category.AIRPLANE or category == Unit.Category.SHIP then - ewRadar = SkynetIADSAWACSRadar:create(earlyWarningRadarUnit, self) - else - ewRadar = SkynetIADSEWRadar:create(earlyWarningRadarUnit, self) - end - ewRadar:setupElements() - ewRadar:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge()) - -- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates - if self.ewRadarScanMistTaskID ~= nil then - self:buildRadarCoverageForEarlyWarningRadar(ewRadar) - end - ewRadar:setActAsEW(true) - ewRadar:setToCorrectAutonomousState() - ewRadar:goLive() - table.insert(self.earlyWarningRadars, ewRadar) - if self:getDebugSettings().addedEWRadar then - self:printOutputToLog("ADDED: "..ewRadar:getDescription()) - end - return ewRadar -end - -function SkynetIADS:getCachedTargetsMaxAge() - return self.contactUpdateInterval -end - -function SkynetIADS:getEarlyWarningRadars() - return self:createTableDelegator(self.earlyWarningRadars) -end - -function SkynetIADS:getEarlyWarningRadarByUnitName(unitName) - for i = 1, #self.earlyWarningRadars do - local ewRadar = self.earlyWarningRadars[i] - if ewRadar:getDCSName() == unitName then - return ewRadar - end - end -end - -function SkynetIADS:findSubString(haystack, needle) - return string.find(haystack, needle, 1, true) -end - -function SkynetIADS:addSAMSitesByPrefix(prefix) - self:deativateSAMSites() - self.samSites = {} - for groupName, groupData in pairs(mist.DBs.groupsByName) do - local pos = self:findSubString(groupName, prefix) - if pos and pos == 1 then - --mist returns groups, units and, StaticObjects - local dcsObject = Group.getByName(groupName) - if dcsObject then - self:addSAMSite(groupName) - end - end - end - return self:createTableDelegator(self.samSites) -end - -function SkynetIADS:getSAMSitesByPrefix(prefix) - local returnSams = {} - for i = 1, #self.samSites do - local samSite = self.samSites[i] - local groupName = samSite:getDCSName() - local pos = self:findSubString(groupName, prefix) - if pos and pos == 1 then - table.insert(returnSams, samSite) - end - end - return self:createTableDelegator(returnSams) -end - -function SkynetIADS:addSAMSite(samSiteName) - local samSiteDCS = Group.getByName(samSiteName) - if samSiteDCS == nil then - self:printOutputToLog("you have added an SAM Site that does not exist, check name of Group in Setup and Mission editor: "..tostring(samSiteName), true) - return - end - self:setCoalition(samSiteDCS) - local samSite = SkynetIADSSamSite:create(samSiteDCS, self) - samSite:setupElements() - samSite:setCanEngageAirWeapons(true) - samSite:goLive() - samSite:setCachedTargetsMaxAge(self:getCachedTargetsMaxAge()) - if samSite:getNatoName() == "UNKNOWN" then - self:printOutputToLog("you have added an SAM site that Skynet IADS can not handle: "..samSite:getDCSName(), true) - samSite:cleanUp() - else - samSite:goDark() - table.insert(self.samSites, samSite) - if self:getDebugSettings().addedSAMSite then - self:printOutputToLog("ADDED: "..samSite:getDescription()) - end - -- for performance improvement, if iads is not scanning no update coverage update needs to be done, will be executed once when iads activates - if self.ewRadarScanMistTaskID ~= nil then - self:buildRadarCoverageForSAMSite(samSite) - end - return samSite - end -end - -function SkynetIADS:getUsableSAMSites() - return self:getUsableAbstractRadarElemtentsOfTable(self.samSites) -end - -function SkynetIADS:getDestroyedSAMSites() - local destroyedSites = {} - for i = 1, #self.samSites do - local samSite = self.samSites[i] - if samSite:isDestroyed() then - table.insert(destroyedSites, samSite) - end - end - return destroyedSites -end - -function SkynetIADS:getSAMSites() - return self:createTableDelegator(self.samSites) -end - -function SkynetIADS:getActiveSAMSites() - local activeSAMSites = {} - for i = 1, #self.samSites do - if self.samSites[i]:isActive() then - table.insert(activeSAMSites, self.samSites[i]) - end - end - return activeSAMSites -end - -function SkynetIADS:getSAMSiteByGroupName(groupName) - for i = 1, #self.samSites do - local samSite = self.samSites[i] - if samSite:getDCSName() == groupName then - return samSite - end - end -end - -function SkynetIADS:getSAMSitesByNatoName(natoName) - local selectedSAMSites = SkynetIADSTableDelegator:create() - for i = 1, #self.samSites do - local samSite = self.samSites[i] - if samSite:getNatoName() == natoName then - table.insert(selectedSAMSites, samSite) - end - end - return selectedSAMSites -end - -function SkynetIADS:addCommandCenter(commandCenter) - self:setCoalition(commandCenter) - local comCenter = SkynetIADSCommandCenter:create(commandCenter, self) - table.insert(self.commandCenters, comCenter) - -- when IADS is active the radars will be added to the new command center. If it not active this will happen when radar coverage is built - if self.ewRadarScanMistTaskID ~= nil then - self:addRadarsToCommandCenters() - end - return comCenter -end - -function SkynetIADS:isCommandCenterUsable() - if #self:getCommandCenters() == 0 then - return true - end - local usableComCenters = self:getUsableAbstractRadarElemtentsOfTable(self:getCommandCenters()) - return (#usableComCenters > 0) -end - -function SkynetIADS:getCommandCenters() - return self.commandCenters -end - - -function SkynetIADS.evaluateContacts(self) - - local ewRadars = self:getUsableEarlyWarningRadars() - local samSites = self:getUsableSAMSites() - - --will add SAM Sites acting as EW Rardars to the ewRadars array: - for i = 1, #samSites do - local samSite = samSites[i] - --We inform SAM sites that a target update is about to happen. If they have no targets in range after the cycle they go dark - samSite:targetCycleUpdateStart() - if samSite:getActAsEW() then - table.insert(ewRadars, samSite) - end - --if the sam site is not in ew mode and active we grab the detected targets right here - if samSite:isActive() and samSite:getActAsEW() == false then - local contacts = samSite:getDetectedTargets() - for j = 1, #contacts do - local contact = contacts[j] - self:mergeContact(contact) - end - end - end - - local samSitesToTrigger = {} - - for i = 1, #ewRadars do - local ewRadar = ewRadars[i] - --call go live in case ewRadar had to shut down (HARM attack) - ewRadar:goLive() - -- if an awacs has traveled more than a predeterminded distance we update the autonomous state of the SAMs - if getmetatable(ewRadar) == SkynetIADSAWACSRadar and ewRadar:isUpdateOfAutonomousStateOfSAMSitesRequired() then - self:buildRadarCoverageForEarlyWarningRadar(ewRadar) - end - local ewContacts = ewRadar:getDetectedTargets() - if #ewContacts > 0 then - local samSitesUnderCoverage = ewRadar:getUsableChildRadars() - for j = 1, #samSitesUnderCoverage do - local samSiteUnterCoverage = samSitesUnderCoverage[j] - -- only if a SAM site is not active we add it to the hash of SAM sites to be iterated later on - if samSiteUnterCoverage:isActive() == false then - --we add them to a hash to make sure each SAM site is in the collection only once, reducing the number of loops we conduct later on - samSitesToTrigger[samSiteUnterCoverage:getDCSName()] = samSiteUnterCoverage - end - end - for j = 1, #ewContacts do - local contact = ewContacts[j] - self:mergeContact(contact) - end - end - end - - self:cleanAgedTargets() - - for samName, samToTrigger in pairs(samSitesToTrigger) do - for j = 1, #self.contacts do - local contact = self.contacts[j] - -- the DCS Radar only returns enemy aircraft, if that should change a coalition check will be required - -- currently every type of object in the air is handed of to the SAM site, including missiles - local description = contact:getDesc() - local category = description.category - if category and category ~= Unit.Category.GROUND_UNIT and category ~= Unit.Category.SHIP and category ~= Unit.Category.STRUCTURE then - samToTrigger:informOfContact(contact) - end - end - end - - for i = 1, #samSites do - local samSite = samSites[i] - samSite:targetCycleUpdateEnd() - end - - self.harmDetection:setContacts(self:getContacts()) - self.harmDetection:evaluateContacts() - - self.logger:printSystemStatus() -end - -function SkynetIADS:cleanAgedTargets() - local contactsToKeep = {} - for i = 1, #self.contacts do - local contact = self.contacts[i] - if contact:getAge() < self.maxTargetAge then - table.insert(contactsToKeep, contact) - end - end - self.contacts = contactsToKeep -end - ---TODO unit test this method: -function SkynetIADS:getAbstracRadarElements() - local abstractRadarElements = {} - local ewRadars = self:getEarlyWarningRadars() - local samSites = self:getSAMSites() - - for i = 1, #ewRadars do - local ewRadar = ewRadars[i] - table.insert(abstractRadarElements, ewRadar) - end - - for i = 1, #samSites do - local samSite = samSites[i] - table.insert(abstractRadarElements, samSite) - end - return abstractRadarElements -end - - -function SkynetIADS:addRadarsToCommandCenters() - - --we clear any existing radars that may have been added earlier - local comCenters = self:getCommandCenters() - for i = 1, #comCenters do - local comCenter = comCenters[i] - comCenter:clearChildRadars() - end - - -- then we add child radars to the command centers - local abstractRadarElements = self:getAbstracRadarElements() - for i = 1, #abstractRadarElements do - local abstractRadar = abstractRadarElements[i] - self:addSingleRadarToCommandCenters(abstractRadar) - end -end - -function SkynetIADS:addSingleRadarToCommandCenters(abstractRadarElement) - local comCenters = self:getCommandCenters() - for i = 1, #comCenters do - local comCenter = comCenters[i] - comCenter:addChildRadar(abstractRadarElement) - end -end - --- this method rebuilds the radar coverage of the IADS, a complete rebuild is only required the first time the IADS is activated --- during runtime it is sufficient to call buildRadarCoverageForSAMSite or buildRadarCoverageForEarlyWarningRadar method that just updates the IADS for one unit, this saves script execution time -function SkynetIADS:buildRadarCoverage() - - --to build the basic radar coverage we use all SAM sites. Checks if SAM site has power or a connection node is done when using the SAM site later on - local samSites = self:getSAMSites() - - --first we clear all child and parent radars that may have been added previously - for i = 1, #samSites do - local samSite = samSites[i] - samSite:clearChildRadars() - samSite:clearParentRadars() - end - - local ewRadars = self:getEarlyWarningRadars() - - for i = 1, #ewRadars do - local ewRadar = ewRadars[i] - ewRadar:clearChildRadars() - end - - --then we rebuild the radar coverage - local abstractRadarElements = self:getAbstracRadarElements() - for i = 1, #abstractRadarElements do - local abstract = abstractRadarElements[i] - self:buildRadarCoverageForAbstractRadarElement(abstract) - end - - self:addRadarsToCommandCenters() - - --we call this once on all sam sites, to make sure autonomous sites go live when IADS activates - for i = 1, #samSites do - local samSite = samSites[i] - samSite:informChildrenOfStateChange() - end - -end - -function SkynetIADS:buildRadarCoverageForAbstractRadarElement(abstractRadarElement) - local abstractRadarElements = self:getAbstracRadarElements() - for i = 1, #abstractRadarElements do - local aElementToCompare = abstractRadarElements[i] - if aElementToCompare ~= abstractRadarElement then - if abstractRadarElement:isInRadarDetectionRangeOf(aElementToCompare) then - self:buildRadarAssociation(aElementToCompare, abstractRadarElement) - end - if aElementToCompare:isInRadarDetectionRangeOf(abstractRadarElement) then - self:buildRadarAssociation(abstractRadarElement, aElementToCompare) - end - end - end -end - -function SkynetIADS:buildRadarAssociation(parent, child) - --chilren should only be SAM sites not EW radars - if ( getmetatable(child) == SkynetIADSSamSite ) then - parent:addChildRadar(child) - end - --Only SAM Sites should have parent Radars, not EW Radars - if ( getmetatable(child) == SkynetIADSSamSite ) then - child:addParentRadar(parent) - end -end - -function SkynetIADS:buildRadarCoverageForSAMSite(samSite) - self:buildRadarCoverageForAbstractRadarElement(samSite) - self:addSingleRadarToCommandCenters(samSite) -end - -function SkynetIADS:buildRadarCoverageForEarlyWarningRadar(ewRadar) - self:buildRadarCoverageForAbstractRadarElement(ewRadar) - self:addSingleRadarToCommandCenters(ewRadar) -end - -function SkynetIADS:mergeContact(contact) - local existingContact = false - for i = 1, #self.contacts do - local iadsContact = self.contacts[i] - if iadsContact:getName() == contact:getName() then - iadsContact:refresh() - --these contacts are used in the logger we set a kown harm state of a contact coming from a SAM site. So the logger will show them als HARMs - contact:setHARMState(iadsContact:getHARMState()) - local radars = contact:getAbstractRadarElementsDetected() - for j = 1, #radars do - local radar = radars[j] - iadsContact:addAbstractRadarElementDetected(radar) - end - existingContact = true - end - end - if existingContact == false then - table.insert(self.contacts, contact) - end -end - - -function SkynetIADS:getContacts() - return self.contacts -end - -function SkynetIADS:getDebugSettings() - return self.logger.debugOutput -end - -function SkynetIADS:printOutput(output, typeWarning) - self.logger:printOutput(output, typeWarning) -end - -function SkynetIADS:printOutputToLog(output) - self.logger:printOutputToLog(output) -end - --- will start going through the Early Warning Radars and SAM sites to check what targets they have detected -function SkynetIADS.activate(self) - mist.removeFunction(self.ewRadarScanMistTaskID) - self.ewRadarScanMistTaskID = mist.scheduleFunction(SkynetIADS.evaluateContacts, {self}, 1, self.contactUpdateInterval) - self:buildRadarCoverage() -end - -function SkynetIADS:setupSAMSitesAndThenActivate(setupTime) - self:activate() - self.iads:printOutputToLog("DEPRECATED: setupSAMSitesAndThenActivate, no longer needed since using enableEmission instead of AI on / off allows for the Ground units to setup with their radars turned off") -end - -function SkynetIADS:deactivate() - mist.removeFunction(self.ewRadarScanMistTaskID) - mist.removeFunction(self.samSetupMistTaskID) - self:deativateSAMSites() - self:deactivateEarlyWarningRadars() - self:deactivateCommandCenters() -end - -function SkynetIADS:deactivateCommandCenters() - for i = 1, #self.commandCenters do - local comCenter = self.commandCenters[i] - comCenter:cleanUp() - end -end - -function SkynetIADS:deativateSAMSites() - for i = 1, #self.samSites do - local samSite = self.samSites[i] - samSite:cleanUp() - end -end - -function SkynetIADS:deactivateEarlyWarningRadars() - for i = 1, #self.earlyWarningRadars do - local ewRadar = self.earlyWarningRadars[i] - ewRadar:cleanUp() - end -end - -function SkynetIADS:addRadioMenu() - self.radioMenu = missionCommands.addSubMenu('SKYNET IADS '..self:getCoalitionString()) - local displayIADSStatus = missionCommands.addCommand('show IADS Status', self.radioMenu, SkynetIADS.updateDisplay, {self = self, value = true, option = 'IADSStatus'}) - local displayIADSStatus = missionCommands.addCommand('hide IADS Status', self.radioMenu, SkynetIADS.updateDisplay, {self = self, value = false, option = 'IADSStatus'}) - local displayIADSStatus = missionCommands.addCommand('show contacts', self.radioMenu, SkynetIADS.updateDisplay, {self = self, value = true, option = 'contacts'}) - local displayIADSStatus = missionCommands.addCommand('hide contacts', self.radioMenu, SkynetIADS.updateDisplay, {self = self, value = false, option = 'contacts'}) -end - -function SkynetIADS:removeRadioMenu() - missionCommands.removeItem(self.radioMenu) -end - -function SkynetIADS.updateDisplay(params) - local option = params.option - local self = params.self - local value = params.value - if option == 'IADSStatus' then - self:getDebugSettings()[option] = value - elseif option == 'contacts' then - self:getDebugSettings()[option] = value - end -end - -function SkynetIADS:getCoalitionString() - local coalitionStr = "RED" - if self.coalitionID == coalition.side.BLUE then - coalitionStr = "BLUE" - elseif self.coalitionID == coalition.side.NEUTRAL then - coalitionStr = "NEUTRAL" - end - - if self.name then - coalitionStr = "COALITION: "..coalitionStr.." | NAME: "..self.name - end - - return coalitionStr -end - -function SkynetIADS:getMooseConnector() - if self.mooseConnector == nil then - self.mooseConnector = SkynetMooseA2ADispatcherConnector:create(self) - end - return self.mooseConnector -end - -function SkynetIADS:addMooseSetGroup(mooseSetGroup) - self:getMooseConnector():addMooseSetGroup(mooseSetGroup) -end - -end -do - -SkynetMooseA2ADispatcherConnector = {} - -function SkynetMooseA2ADispatcherConnector:create(iads) - local instance = {} - setmetatable(instance, self) - self.__index = self - instance.iadsCollection = {} - instance.mooseGroups = {} - instance.ewRadarGroupNames = {} - instance.samSiteGroupNames = {} - table.insert(instance.iadsCollection, iads) - return instance -end - -function SkynetMooseA2ADispatcherConnector:addIADS(iads) - table.insert(self.iadsCollection, iads) -end - -function SkynetMooseA2ADispatcherConnector:addMooseSetGroup(mooseSetGroup) - table.insert(self.mooseGroups, mooseSetGroup) - self:update() -end - -function SkynetMooseA2ADispatcherConnector:getEarlyWarningRadarGroupNames() - self.ewRadarGroupNames = {} - for i = 1, #self.iadsCollection do - local ewRadars = self.iadsCollection[i]:getUsableEarlyWarningRadars() - for j = 1, #ewRadars do - local ewRadar = ewRadars[j] - table.insert(self.ewRadarGroupNames, ewRadar:getDCSRepresentation():getGroup():getName()) - end - end - return self.ewRadarGroupNames -end - -function SkynetMooseA2ADispatcherConnector:getSAMSiteGroupNames() - self.samSiteGroupNames = {} - for i = 1, #self.iadsCollection do - local samSites = self.iadsCollection[i]:getUsableSAMSites() - for j = 1, #samSites do - local samSite = samSites[j] - table.insert(self.samSiteGroupNames, samSite:getDCSName()) - end - end - return self.samSiteGroupNames -end - -function SkynetMooseA2ADispatcherConnector:update() - - --mooseGroup elements are type of: - --https://flightcontrol-master.github.io/MOOSE_DOCS_DEVELOP/Documentation/Core.Set.html##(SET_GROUP) - - --remove previously set group names: - for i = 1, #self.mooseGroups do - local mooseGroup = self.mooseGroups[i] - mooseGroup:RemoveGroupsByName(self.ewRadarGroupNames) - mooseGroup:RemoveGroupsByName(self.samSiteGroupNames) - end - - --add group names of IADS radars that are currently usable by the IADS: - for i = 1, #self.mooseGroups do - local mooseGroup = self.mooseGroups[i] - mooseGroup:AddGroupsByName(self:getEarlyWarningRadarGroupNames()) - mooseGroup:AddGroupsByName(self:getSAMSiteGroupNames()) - end -end - -end -do - - -SkynetIADSTableDelegator = {} - -function SkynetIADSTableDelegator:create() - local instance = {} - local forwarder = {} - forwarder.__index = function(tbl, name) - tbl[name] = function(self, ...) - for i = 1, #self do - self[i][name](self[i], ...) - end - return self - end - return tbl[name] - end - setmetatable(instance, forwarder) - instance.__index = forwarder - return instance -end - -end -do - -SkynetIADSAbstractDCSObjectWrapper = {} - -function SkynetIADSAbstractDCSObjectWrapper:create(dcsRepresentation) - local instance = {} - setmetatable(instance, self) - self.__index = self - instance.dcsName = "" - instance.typeName = "" - instance:setDCSRepresentation(dcsRepresentation) - if getmetatable(dcsRepresentation) ~= Group then - instance.typeName = dcsRepresentation:getTypeName() - end - return instance -end - -function SkynetIADSAbstractDCSObjectWrapper:setDCSRepresentation(representation) - self.dcsRepresentation = representation - if self.dcsRepresentation then - self.dcsName = self:getDCSRepresentation():getName() - end -end - -function SkynetIADSAbstractDCSObjectWrapper:getDCSRepresentation() - return self.dcsRepresentation -end - -function SkynetIADSAbstractDCSObjectWrapper:getName() - return self.dcsName -end - -function SkynetIADSAbstractDCSObjectWrapper:getTypeName() - return self.typeName -end - -function SkynetIADSAbstractDCSObjectWrapper:getPosition() - return self.dcsRepresentation:getPosition() -end - -function SkynetIADSAbstractDCSObjectWrapper:isExist() - if self.dcsRepresentation then - return self.dcsRepresentation:isExist() - else - return false - end -end - -function SkynetIADSAbstractDCSObjectWrapper:insertToTableIfNotAlreadyAdded(tbl, object) - local isAdded = false - for i = 1, #tbl do - local child = tbl[i] - if child == object then - isAdded = true - end - end - if isAdded == false then - table.insert(tbl, object) - end - return not isAdded -end - --- helper code for class inheritance -function inheritsFrom( baseClass ) - - local new_class = {} - local class_mt = { __index = new_class } - - function new_class:create() - local newinst = {} - setmetatable( newinst, class_mt ) - return newinst - end - - if nil ~= baseClass then - setmetatable( new_class, { __index = baseClass } ) - end - - -- Implementation of additional OO properties starts here -- - - -- Return the class object of the instance - function new_class:class() - return new_class - end - - -- Return the super class object of the instance - function new_class:superClass() - return baseClass - end - - -- Return true if the caller is an instance of theClass - function new_class:isa( theClass ) - local b_isa = false - - local cur_class = new_class - - while ( nil ~= cur_class ) and ( false == b_isa ) do - if cur_class == theClass then - b_isa = true - else - cur_class = cur_class:superClass() - end - end - - return b_isa - end - - return new_class -end - - -end - -do - -SkynetIADSAbstractElement = {} -SkynetIADSAbstractElement = inheritsFrom(SkynetIADSAbstractDCSObjectWrapper) - -function SkynetIADSAbstractElement:create(dcsRepresentation, iads) - local instance = self:superClass():create(dcsRepresentation) - setmetatable(instance, self) - self.__index = self - instance.connectionNodes = {} - instance.powerSources = {} - instance.iads = iads - instance.natoName = "UNKNOWN" - world.addEventHandler(instance) - return instance -end - -function SkynetIADSAbstractElement:removeEventHandlers() - world.removeEventHandler(self) -end - -function SkynetIADSAbstractElement:cleanUp() - self:removeEventHandlers() -end - -function SkynetIADSAbstractElement:isDestroyed() - return self:getDCSRepresentation():isExist() == false -end - -function SkynetIADSAbstractElement:addPowerSource(powerSource) - table.insert(self.powerSources, powerSource) - self:informChildrenOfStateChange() - return self -end - -function SkynetIADSAbstractElement:getPowerSources() - return self.powerSources -end - -function SkynetIADSAbstractElement:addConnectionNode(connectionNode) - table.insert(self.connectionNodes, connectionNode) - self:informChildrenOfStateChange() - return self -end - -function SkynetIADSAbstractElement:getConnectionNodes() - return self.connectionNodes -end - -function SkynetIADSAbstractElement:hasActiveConnectionNode() - local connectionNode = self:genericCheckOneObjectIsAlive(self.connectionNodes) - if connectionNode == false and self.iads:getDebugSettings().samNoConnection then - self.iads:printOutput(self:getDescription().." no connection to Command Center") - end - return connectionNode -end - -function SkynetIADSAbstractElement:hasWorkingPowerSource() - local power = self:genericCheckOneObjectIsAlive(self.powerSources) - if power == false and self.iads:getDebugSettings().hasNoPower then - self.iads:printOutput(self:getDescription().." has no power") - end - return power -end - -function SkynetIADSAbstractElement:getDCSName() - return self.dcsName -end - --- generic function to theck if power plants, command centers, connection nodes are still alive -function SkynetIADSAbstractElement:genericCheckOneObjectIsAlive(objects) - local isAlive = (#objects == 0) - for i = 1, #objects do - local object = objects[i] - --if we find one object that is not fully destroyed we assume the IADS is still working - if object:isExist() then - isAlive = true - break - end - end - return isAlive -end - -function SkynetIADSAbstractElement:getNatoName() - return self.natoName -end - -function SkynetIADSAbstractElement:getDescription() - return "IADS ELEMENT: "..self:getDCSName().." | Type: "..tostring(self:getNatoName()) -end - -function SkynetIADSAbstractElement:onEvent(event) - --if a unit is destroyed we check to see if its a power plant powering the unit or a connection node - if event.id == world.event.S_EVENT_DEAD then - if self:hasWorkingPowerSource() == false or self:isDestroyed() then - self:goDark() - self:informChildrenOfStateChange() - end - if self:hasActiveConnectionNode() == false then - self:informChildrenOfStateChange() - end - end - if event.id == world.event.S_EVENT_SHOT then - self:weaponFired(event) - end -end - ---placeholder method, can be implemented by subclasses -function SkynetIADSAbstractElement:weaponFired(event) - -end - ---placeholder method, can be implemented by subclasses -function SkynetIADSAbstractElement:goDark() - -end - ---placeholder method, can be implemented by subclasses -function SkynetIADSAbstractElement:goAutonomous() - -end - ---placeholder method, can be implemented by subclasses -function SkynetIADSAbstractElement:setToCorrectAutonomousState() - -end - ---placeholder method, can be implemented by subclasses -function SkynetIADSAbstractElement:informChildrenOfStateChange() - -end - -end -do - -SkynetIADSAbstractRadarElement = {} -SkynetIADSAbstractRadarElement = inheritsFrom(SkynetIADSAbstractElement) - -SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI = 1 -SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DARK = 2 - -SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE = 1 -SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_SEARCH_RANGE = 2 - -SkynetIADSAbstractRadarElement.HARM_TO_SAM_ASPECT = 15 -SkynetIADSAbstractRadarElement.HARM_LOOKAHEAD_NM = 20 - -function SkynetIADSAbstractRadarElement:create(dcsElementWithRadar, iads) - local instance = self:superClass():create(dcsElementWithRadar, iads) - setmetatable(instance, self) - self.__index = self - instance.aiState = false - instance.harmScanID = nil - instance.harmSilenceID = nil - instance.lastJammerUpdate = 0 - instance.objectsIdentifiedAsHarms = {} - instance.objectsIdentifiedAsHarmsMaxTargetAge = 60 - instance.launchers = {} - instance.trackingRadars = {} - instance.searchRadars = {} - instance.parentRadars = {} - instance.childRadars = {} - instance.missilesInFlight = {} - instance.pointDefences = {} - instance.harmDecoys = {} - instance.autonomousBehaviour = SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI - instance.goLiveRange = SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE - instance.isAutonomous = true - instance.harmDetectionChance = 0 - instance.minHarmShutdownTime = 0 - instance.maxHarmShutDownTime = 0 - instance.minHarmPresetShutdownTime = 30 - instance.maxHarmPresetShutdownTime = 180 - instance.harmShutdownTime = 0 - instance.firingRangePercent = 100 - instance.actAsEW = false - instance.cachedTargets = {} - instance.cachedTargetsMaxAge = 1 - instance.cachedTargetsCurrentAge = 0 - instance.goLiveTime = 0 - instance.engageAirWeapons = false - instance.isAPointDefence = false - instance.canEngageHARM = false - instance.dataBaseSupportedTypesCanEngageHARM = false - -- 5 seconds seems to be a good value for the sam site to find the target with its organic radar - instance.noCacheActiveForSecondsAfterGoLive = 5 - return instance -end - ---TODO: this method could be updated to only return Radar weapons fired, this way a SAM firing an IR weapon could go dark faster in the goDark() method -function SkynetIADSAbstractRadarElement:weaponFired(event) - if event.id == world.event.S_EVENT_SHOT then - local weapon = event.weapon - local launcherFired = event.initiator - for i = 1, #self.launchers do - local launcher = self.launchers[i] - if launcher:getDCSRepresentation() == launcherFired then - table.insert(self.missilesInFlight, weapon) - end - end - end -end - -function SkynetIADSAbstractRadarElement:setCachedTargetsMaxAge(maxAge) - self.cachedTargetsMaxAge = maxAge -end - -function SkynetIADSAbstractRadarElement:cleanUp() - for i = 1, #self.pointDefences do - local pointDefence = self.pointDefences[i] - pointDefence:cleanUp() - end - mist.removeFunction(self.harmScanID) - mist.removeFunction(self.harmSilenceID) - --call method from super class - self:removeEventHandlers() -end - -function SkynetIADSAbstractRadarElement:setIsAPointDefence(state) - if (state == true or state == false) then - self.isAPointDefence = state - end -end - -function SkynetIADSAbstractRadarElement:getIsAPointDefence() - return self.isAPointDefence -end - -function SkynetIADSAbstractRadarElement:addPointDefence(pointDefence) - table.insert(self.pointDefences, pointDefence) - pointDefence:setIsAPointDefence(true) - return self -end - -function SkynetIADSAbstractRadarElement:getPointDefences() - return self.pointDefences -end - -function SkynetIADSAbstractRadarElement:addHARMDecoy(harmDecoy) - table.insert(self.harmDecoys, harmDecoy) -end - -function SkynetIADSAbstractRadarElement:addParentRadar(parentRadar) - self:insertToTableIfNotAlreadyAdded(self.parentRadars, parentRadar) - self:informChildrenOfStateChange() -end - -function SkynetIADSAbstractRadarElement:getParentRadars() - return self.parentRadars -end - -function SkynetIADSAbstractRadarElement:clearParentRadars() - self.parentRadars = {} -end - -function SkynetIADSAbstractRadarElement:addChildRadar(childRadar) - self:insertToTableIfNotAlreadyAdded(self.childRadars, childRadar) -end - -function SkynetIADSAbstractRadarElement:getChildRadars() - return self.childRadars -end - -function SkynetIADSAbstractRadarElement:clearChildRadars() - self.childRadars = {} -end - ---TODO: unit test this method -function SkynetIADSAbstractRadarElement:getUsableChildRadars() - local usableRadars = {} - for i = 1, #self.childRadars do - local childRadar = self.childRadars[i] - if childRadar:hasWorkingPowerSource() and childRadar:hasActiveConnectionNode() then - table.insert(usableRadars, childRadar) - end - end - return usableRadars -end - -function SkynetIADSAbstractRadarElement:informChildrenOfStateChange() - self:setToCorrectAutonomousState() - local children = self:getChildRadars() - for i = 1, #children do - local childRadar = children[i] - childRadar:setToCorrectAutonomousState() - end - self.iads:getMooseConnector():update() -end - -function SkynetIADSAbstractRadarElement:setToCorrectAutonomousState() - local parents = self:getParentRadars() - for i = 1, #parents do - local parent = parents[i] - --of one parent exists that still is connected to the IADS, the SAM site does not have to go autonomous - --instead of isDestroyed() write method, hasWorkingSearchRadars() - if self:hasActiveConnectionNode() and self.iads:isCommandCenterUsable() and parent:hasWorkingPowerSource() and parent:hasActiveConnectionNode() and parent:getActAsEW() == true and parent:isDestroyed() == false then - self:resetAutonomousState() - return - end - end - self:goAutonomous() -end - - -function SkynetIADSAbstractRadarElement:setAutonomousBehaviour(mode) - if mode ~= nil then - self.autonomousBehaviour = mode - end - return self -end - -function SkynetIADSAbstractRadarElement:getAutonomousBehaviour() - return self.autonomousBehaviour -end - -function SkynetIADSAbstractRadarElement:resetAutonomousState() - self.isAutonomous = false - self:goDark() -end - -function SkynetIADSAbstractRadarElement:goAutonomous() - self.isAutonomous = true - if self.autonomousBehaviour == SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DARK then - self:goDark() - else - self:goLive() - end -end - -function SkynetIADSAbstractRadarElement:getAutonomousState() - return self.isAutonomous -end - -function SkynetIADSAbstractRadarElement:pointDefencesHaveRemainingAmmo(minNumberOfMissiles) - local remainingMissiles = 0 - for i = 1, #self.pointDefences do - local pointDefence = self.pointDefences[i] - remainingMissiles = remainingMissiles + pointDefence:getRemainingNumberOfMissiles() - end - return self:hasRequiredNumberOfMissiles(minNumberOfMissiles, remainingMissiles) -end - -function SkynetIADSAbstractRadarElement:hasRequiredNumberOfMissiles(minNumberOfMissiles, remainingMissiles) - local returnValue = false - if ( remainingMissiles > 0 and remainingMissiles >= minNumberOfMissiles ) then - returnValue = true - end - return returnValue -end - -function SkynetIADSAbstractRadarElement:hasRemainingAmmoToEngageMissiles(minNumberOfMissiles) - local remainingMissiles = self:getRemainingNumberOfMissiles() - return self:hasRequiredNumberOfMissiles(minNumberOfMissiles, remainingMissiles) -end - --- this method needs to be refactored so that it works for ew radars that don't have launchers, or that it is only called by sam sites -function SkynetIADSAbstractRadarElement:hasEnoughLaunchersToEngageMissiles(minNumberOfLaunchers) - local launchers = self:getLaunchers() - if(launchers ~= nil) then - launchers = #self:getLaunchers() - else - launchers = 0 - end - return self:hasRequiredNumberOfMissiles(minNumberOfLaunchers, launchers) -end - -function SkynetIADSAbstractRadarElement:pointDefencesHaveEnoughLaunchers(minNumberOfLaunchers) - local numOfLaunchers = 0 - for i = 1, #self.pointDefences do - local pointDefence = self.pointDefences[i] - numOfLaunchers = numOfLaunchers + #pointDefence:getLaunchers() - end - return self:hasRequiredNumberOfMissiles(minNumberOfLaunchers, numOfLaunchers) -end - -function SkynetIADSAbstractRadarElement:setIgnoreHARMSWhilePointDefencesHaveAmmo(state) - self.iads:printOutputToLog("DEPRECATED: setIgnoreHARMSWhilePointDefencesHaveAmmo SAM Site will stay live automaticall as long as itself or it's point defences can defend against a HARM") - return self -end - -function SkynetIADSAbstractRadarElement:hasMissilesInFlight() - return #self.missilesInFlight > 0 -end - -function SkynetIADSAbstractRadarElement:getNumberOfMissilesInFlight() - return #self.missilesInFlight -end - --- DCS does not send an event, when a missile is destroyed, so this method needs to be polled so that the missiles in flight are current, polling is done in the HARM Search call: evaluateIfTargetsContainHARMs -function SkynetIADSAbstractRadarElement:updateMissilesInFlight() - local missilesInFlight = {} - for i = 1, #self.missilesInFlight do - local missile = self.missilesInFlight[i] - if missile:isExist() then - table.insert(missilesInFlight, missile) - end - end - self.missilesInFlight = missilesInFlight - self:goDarkIfOutOfAmmo() -end - -function SkynetIADSAbstractRadarElement:goDarkIfOutOfAmmo() - if self:hasRemainingAmmo() == false and self:getActAsEW() == false then - self:goDark() - end -end - -function SkynetIADSAbstractRadarElement:getActAsEW() - return self.actAsEW -end - -function SkynetIADSAbstractRadarElement:setActAsEW(ewState) - if ewState == true or ewState == false then - local stateChange = false - if ewState ~= self.actAsEW then - stateChange = true - end - self.actAsEW = ewState - if stateChange then - self:informChildrenOfStateChange() - end - end - if self.actAsEW == true then - self:goLive() - else - self:goDark() - end - return self -end - -function SkynetIADSAbstractRadarElement:getUnitsToAnalyse() - local units = {} - table.insert(units, self:getDCSRepresentation()) - if getmetatable(self:getDCSRepresentation()) == Group then - units = self:getDCSRepresentation():getUnits() - end - return units -end - -function SkynetIADSAbstractRadarElement:getRemainingNumberOfMissiles() - local remainingNumberOfMissiles = 0 - for i = 1, #self.launchers do - local launcher = self.launchers[i] - remainingNumberOfMissiles = remainingNumberOfMissiles + launcher:getRemainingNumberOfMissiles() - end - return remainingNumberOfMissiles -end - -function SkynetIADSAbstractRadarElement:getInitialNumberOfMissiles() - local initalNumberOfMissiles = 0 - for i = 1, #self.launchers do - local launcher = self.launchers[i] - initalNumberOfMissiles = launcher:getInitialNumberOfMissiles() + initalNumberOfMissiles - end - return initalNumberOfMissiles -end - -function SkynetIADSAbstractRadarElement:getRemainingNumberOfShells() - local remainingNumberOfShells = 0 - for i = 1, #self.launchers do - local launcher = self.launchers[i] - remainingNumberOfShells = remainingNumberOfShells + launcher:getRemainingNumberOfShells() - end - return remainingNumberOfShells -end - -function SkynetIADSAbstractRadarElement:getInitialNumberOfShells() - local initialNumberOfShells = 0 - for i = 1, #self.launchers do - local launcher = self.launchers[i] - initialNumberOfShells = initialNumberOfShells + launcher:getInitialNumberOfShells() - end - return initialNumberOfShells -end - -function SkynetIADSAbstractRadarElement:hasRemainingAmmo() - --the launcher check is due to ew radars they have no launcher and no ammo and therefore are never out of ammo - return ( #self.launchers == 0 ) or ((self:getRemainingNumberOfMissiles() > 0 ) or ( self:getRemainingNumberOfShells() > 0 ) ) -end - -function SkynetIADSAbstractRadarElement:getHARMDetectionChance() - return self.harmDetectionChance -end - -function SkynetIADSAbstractRadarElement:setHARMDetectionChance(chance) - if chance and chance >= 0 and chance <= 100 then - self.harmDetectionChance = chance - end - return self -end - -function SkynetIADSAbstractRadarElement:setupElements() - local numUnits = #self:getUnitsToAnalyse() - for typeName, dataType in pairs(SkynetIADS.database) do - local hasSearchRadar = false - local hasTrackingRadar = false - local hasLauncher = false - self.searchRadars = {} - self.trackingRadars = {} - self.launchers = {} - for entry, unitData in pairs(dataType) do - if entry == 'searchRadar' then - self:analyseAndAddUnit(SkynetIADSSAMSearchRadar, self.searchRadars, unitData) - hasSearchRadar = true - end - if entry == 'launchers' then - self:analyseAndAddUnit(SkynetIADSSAMLauncher, self.launchers, unitData) - hasLauncher = true - end - if entry == 'trackingRadar' then - self:analyseAndAddUnit(SkynetIADSSAMTrackingRadar, self.trackingRadars, unitData) - hasTrackingRadar = true - end - end - - --this check ensures a unit or group has all required elements for the specific sam or ew type: - if (hasLauncher and hasSearchRadar and hasTrackingRadar and #self.launchers > 0 and #self.searchRadars > 0 and #self.trackingRadars > 0 ) - or (hasSearchRadar and hasLauncher and #self.searchRadars > 0 and #self.launchers > 0) then - self:setHARMDetectionChance(dataType['harm_detection_chance']) - self.dataBaseSupportedTypesCanEngageHARM = dataType['can_engage_harm'] - self:setCanEngageHARM(self.dataBaseSupportedTypesCanEngageHARM) - local natoName = dataType['name']['NATO'] - self:buildNatoName(natoName) - break - end - end -end - -function SkynetIADSAbstractRadarElement:setCanEngageHARM(canEngage) - if canEngage == true or canEngage == false then - self.canEngageHARM = canEngage - if ( canEngage == true and self:getCanEngageAirWeapons() == false ) then - self:setCanEngageAirWeapons(true) - end - end - return self -end - -function SkynetIADSAbstractRadarElement:getCanEngageHARM() - return self.canEngageHARM -end - -function SkynetIADSAbstractRadarElement:setCanEngageAirWeapons(engageAirWeapons) - if self:isDestroyed() == false then - local controller = self:getDCSRepresentation():getController() - if ( engageAirWeapons == true ) then - controller:setOption(AI.Option.Ground.id.ENGAGE_AIR_WEAPONS, true) - --its important that we set var to true here, to prevent recursion in setCanEngageHARM - self.engageAirWeapons = true - --we set the original value we got when loading info about the SAM site - self:setCanEngageHARM(self.dataBaseSupportedTypesCanEngageHARM) - else - controller:setOption(AI.Option.Ground.id.ENGAGE_AIR_WEAPONS, false) - self:setCanEngageHARM(false) - self.engageAirWeapons = false - end - end - return self -end - -function SkynetIADSAbstractRadarElement:getCanEngageAirWeapons() - return self.engageAirWeapons -end - -function SkynetIADSAbstractRadarElement:buildNatoName(natoName) - --we shorten the SA-XX names and don't return their code names eg goa, gainful.. - local pos = natoName:find(" ") - local prefix = natoName:sub(1, 2) - if string.lower(prefix) == 'sa' and pos ~= nil then - self.natoName = natoName:sub(1, (pos-1)) - else - self.natoName = natoName - end -end - -function SkynetIADSAbstractRadarElement:analyseAndAddUnit(class, tableToAdd, unitData) - local units = self:getUnitsToAnalyse() - for i = 1, #units do - local unit = units[i] - self:buildSingleUnit(unit, class, tableToAdd, unitData) - end -end - -function SkynetIADSAbstractRadarElement:buildSingleUnit(unit, class, tableToAdd, unitData) - local unitTypeName = unit:getTypeName() - for unitName, unitPerformanceData in pairs(unitData) do - if unitName == unitTypeName then - samElement = class:create(unit) - samElement:setupRangeData() - table.insert(tableToAdd, samElement) - end - end -end - -function SkynetIADSAbstractRadarElement:getController() - local dcsRepresentation = self:getDCSRepresentation() - if dcsRepresentation:isExist() then - return dcsRepresentation:getController() - else - return nil - end -end - -function SkynetIADSAbstractRadarElement:getLaunchers() - return self.launchers -end - -function SkynetIADSAbstractRadarElement:getSearchRadars() - return self.searchRadars -end - -function SkynetIADSAbstractRadarElement:getTrackingRadars() - return self.trackingRadars -end - -function SkynetIADSAbstractRadarElement:getRadars() - local radarUnits = {} - for i = 1, #self.searchRadars do - table.insert(radarUnits, self.searchRadars[i]) - end - for i = 1, #self.trackingRadars do - table.insert(radarUnits, self.trackingRadars[i]) - end - return radarUnits -end - -function SkynetIADSAbstractRadarElement:setGoLiveRangeInPercent(percent) - if percent ~= nil then - self.firingRangePercent = percent - for i = 1, #self.launchers do - local launcher = self.launchers[i] - launcher:setFiringRangePercent(self.firingRangePercent) - end - for i = 1, #self.searchRadars do - local radar = self.searchRadars[i] - radar:setFiringRangePercent(self.firingRangePercent) - end - end - return self -end - -function SkynetIADSAbstractRadarElement:getGoLiveRangeInPercent() - return self.firingRangePercent -end - -function SkynetIADSAbstractRadarElement:setEngagementZone(engagementZone) - if engagementZone == SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE then - self.goLiveRange = engagementZone - elseif engagementZone == SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_SEARCH_RANGE then - self.goLiveRange = engagementZone - end - return self -end - -function SkynetIADSAbstractRadarElement:getEngagementZone() - return self.goLiveRange -end - -function SkynetIADSAbstractRadarElement:goLive() - if ( self.aiState == false and self:hasWorkingPowerSource() and self.harmSilenceID == nil) - and (self:hasRemainingAmmo() == true ) - then - if self:isDestroyed() == false then - local cont = self:getController() - cont:setOption(AI.Option.Ground.id.ALARM_STATE, AI.Option.Ground.val.ALARM_STATE.RED) - cont:setOption(AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE) - self:getDCSRepresentation():enableEmission(true) - self.goLiveTime = timer.getTime() - self.aiState = true - end - self:pointDefencesStopActingAsEW() - if self.iads:getDebugSettings().radarWentLive then - self.iads:printOutputToLog("GOING LIVE: "..self:getDescription()) - end - self:scanForHarms() - end -end - -function SkynetIADSAbstractRadarElement:pointDefencesStopActingAsEW() - for i = 1, #self.pointDefences do - local pointDefence = self.pointDefences[i] - pointDefence:setActAsEW(false) - end -end - - -function SkynetIADSAbstractRadarElement:goDark() - if (self:hasWorkingPowerSource() == false) or ( self.aiState == true ) - and (self.harmSilenceID ~= nil or ( self.harmSilenceID == nil and #self:getDetectedTargets() == 0 and self:hasMissilesInFlight() == false) or ( self.harmSilenceID == nil and #self:getDetectedTargets() > 0 and self:hasMissilesInFlight() == false and self:hasRemainingAmmo() == false ) ) - then - if self:isDestroyed() == false then - self:getDCSRepresentation():enableEmission(false) - end - -- point defence will only go live if the Radar Emitting site it is protecting goes dark and this is due to a it defending against a HARM - if (self.harmSilenceID ~= nil) then - self:pointDefencesGoLive() - end - self.aiState = false - self:stopScanningForHARMs() - if self.iads:getDebugSettings().radarWentDark then - self.iads:printOutputToLog("GOING DARK: "..self:getDescription()) - end - end -end - -function SkynetIADSAbstractRadarElement:pointDefencesGoLive() - local setActive = false - for i = 1, #self.pointDefences do - local pointDefence = self.pointDefences[i] - if ( pointDefence:getActAsEW() == false ) then - setActive = true - pointDefence:setActAsEW(true) - end - end - return setActive -end - -function SkynetIADSAbstractRadarElement:isActive() - return self.aiState -end - -function SkynetIADSAbstractRadarElement:isTargetInRange(target) - - local isSearchRadarInRange = false - local isTrackingRadarInRange = false - local isLauncherInRange = false - - local isSearchRadarInRange = ( #self.searchRadars == 0 ) - for i = 1, #self.searchRadars do - local searchRadar = self.searchRadars[i] - if searchRadar:isInRange(target) then - isSearchRadarInRange = true - break - end - end - - if self.goLiveRange == SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE then - - isLauncherInRange = ( #self.launchers == 0 ) - for i = 1, #self.launchers do - local launcher = self.launchers[i] - if launcher:isInRange(target) then - isLauncherInRange = true - break - end - end - - isTrackingRadarInRange = ( #self.trackingRadars == 0 ) - for i = 1, #self.trackingRadars do - local trackingRadar = self.trackingRadars[i] - if trackingRadar:isInRange(target) then - isTrackingRadarInRange = true - break - end - end - else - isLauncherInRange = true - isTrackingRadarInRange = true - end - return (isSearchRadarInRange and isTrackingRadarInRange and isLauncherInRange ) -end - -function SkynetIADSAbstractRadarElement:isInRadarDetectionRangeOf(abstractRadarElement) - local radars = self:getRadars() - local abstractRadarElementRadars = abstractRadarElement:getRadars() - for i = 1, #radars do - local radar = radars[i] - for j = 1, #abstractRadarElementRadars do - local abstractRadarElementRadar = abstractRadarElementRadars[j] - if abstractRadarElementRadar:isExist() and radar:isExist() then - local distance = self:getDistanceToUnit(radar:getDCSRepresentation():getPosition().p, abstractRadarElementRadar:getDCSRepresentation():getPosition().p) - if abstractRadarElementRadar:getMaxRangeFindingTarget() >= distance then - return true - end - end - end - end - return false -end - -function SkynetIADSAbstractRadarElement:getDistanceToUnit(unitPosA, unitPosB) - return mist.utils.round(mist.utils.get2DDist(unitPosA, unitPosB, 0)) -end - -function SkynetIADSAbstractRadarElement:hasWorkingRadar() - local radars = self:getRadars() - for i = 1, #radars do - local radar = radars[i] - if radar:isRadarWorking() == true then - return true - end - end - return false -end - -function SkynetIADSAbstractRadarElement:jam(successProbability) - if self:isDestroyed() == false then - local controller = self:getController() - local probability = math.random(1, 100) - if self.iads:getDebugSettings().jammerProbability then - self.iads:printOutputToLog("JAMMER: "..self:getDescription()..": Probability: "..successProbability) - end - if successProbability > probability then - controller:setOption(AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_HOLD) - if self.iads:getDebugSettings().jammerProbability then - self.iads:printOutputToLog("JAMMER: "..self:getDescription()..": jammed, setting to weapon hold") - end - else - controller:setOption(AI.Option.Air.id.ROE, AI.Option.Air.val.ROE.WEAPON_FREE) - if self.iads:getDebugSettings().jammerProbability then - self.iads:printOutputToLog("JAMMER: "..self:getDescription()..": jammed, setting to weapon free") - end - end - self.lastJammerUpdate = timer:getTime() - end -end - -function SkynetIADSAbstractRadarElement:scanForHarms() - self:stopScanningForHARMs() - self.harmScanID = mist.scheduleFunction(SkynetIADSAbstractRadarElement.evaluateIfTargetsContainHARMs, {self}, 1, 2) -end - -function SkynetIADSAbstractRadarElement:isScanningForHARMs() - return self.harmScanID ~= nil -end - -function SkynetIADSAbstractRadarElement:isDefendingHARM() - return self.harmSilenceID ~= nil -end - -function SkynetIADSAbstractRadarElement:stopScanningForHARMs() - mist.removeFunction(self.harmScanID) - self.harmScanID = nil -end - -function SkynetIADSAbstractRadarElement:goSilentToEvadeHARM(timeToImpact) - self:finishHarmDefence(self) - if ( timeToImpact == nil ) then - timeToImpact = 0 - end - - self.minHarmShutdownTime = self:calculateMinimalShutdownTimeInSeconds(timeToImpact) - self.maxHarmShutDownTime = self:calculateMaximalShutdownTimeInSeconds(self.minHarmShutdownTime) - - self.harmShutdownTime = self:calculateHARMShutdownTime() - if self.iads:getDebugSettings().harmDefence then - self.iads:printOutputToLog("HARM DEFENCE SHUTTING DOWN: "..self:getDCSName().." | FOR: "..self.harmShutdownTime.." seconds | TTI: "..timeToImpact) - end - self.harmSilenceID = mist.scheduleFunction(SkynetIADSAbstractRadarElement.finishHarmDefence, {self}, timer.getTime() + self.harmShutdownTime, 1) - self:goDark() -end - -function SkynetIADSAbstractRadarElement:getHARMShutdownTime() - return self.harmShutdownTime -end - -function SkynetIADSAbstractRadarElement:calculateHARMShutdownTime() - local shutDownTime = math.random(self.minHarmShutdownTime, self.maxHarmShutDownTime) - return shutDownTime -end - -function SkynetIADSAbstractRadarElement.finishHarmDefence(self) - mist.removeFunction(self.harmSilenceID) - self.harmSilenceID = nil - self.harmShutdownTime = 0 - - if ( self:getAutonomousState() == true ) then - self:goAutonomous() - end -end - -function SkynetIADSAbstractRadarElement:getDetectedTargets() - if ( timer.getTime() - self.cachedTargetsCurrentAge > self.cachedTargetsMaxAge ) or ( timer.getTime() - self.goLiveTime < self.noCacheActiveForSecondsAfterGoLive ) then - self.cachedTargets = {} - self.cachedTargetsCurrentAge = timer.getTime() - if self:hasWorkingPowerSource() and self:isDestroyed() == false then - local targets = self:getController():getDetectedTargets(Controller.Detection.RADAR) - for i = 1, #targets do - local target = targets[i] - -- there are cases when a destroyed object is still visible as a target to the radar, don't add it, will cause errors everywhere the dcs object is accessed - if target.object then - local iadsTarget = SkynetIADSContact:create(target, self) - iadsTarget:refresh() - if self:isTargetInRange(iadsTarget) then - table.insert(self.cachedTargets, iadsTarget) - end - end - end - end - end - return self.cachedTargets -end - -function SkynetIADSAbstractRadarElement:getSecondsToImpact(distanceNM, speedKT) - local tti = 0 - if speedKT > 0 then - tti = mist.utils.round((distanceNM / speedKT) * 3600, 0) - if tti < 0 then - tti = 0 - end - end - return tti -end - -function SkynetIADSAbstractRadarElement:getDistanceInMetersToContact(radarUnit, point) - return mist.utils.round(mist.utils.get3DDist(radarUnit:getPosition().p, point), 0) -end - -function SkynetIADSAbstractRadarElement:calculateMinimalShutdownTimeInSeconds(timeToImpact) - return timeToImpact + self.minHarmPresetShutdownTime -end - -function SkynetIADSAbstractRadarElement:calculateMaximalShutdownTimeInSeconds(minShutdownTime) - return minShutdownTime + mist.random(1, self.maxHarmPresetShutdownTime) -end - -function SkynetIADSAbstractRadarElement:calculateImpactPoint(target, distanceInMeters) - -- distance needs to be incremented by a certain value for ip calculation to work, check why presumably due to rounding errors in the previous distance calculation - return land.getIP(target:getPosition().p, target:getPosition().x, distanceInMeters + 50) -end - -function SkynetIADSAbstractRadarElement:shallReactToHARM() - return self.harmDetectionChance >= math.random(1, 100) -end - --- will only check for missiles, if DCS ads AAA than can engage HARMs then this code must be updated: -function SkynetIADSAbstractRadarElement:shallIgnoreHARMShutdown() - local numOfHarms = self:getNumberOfObjectsItentifiedAsHARMS() - --[[ - self.iads:printOutputToLog("Self enough launchers: "..tostring(self:hasEnoughLaunchersToEngageMissiles(numOfHarms))) - self.iads:printOutputToLog("Self enough missiles: "..tostring(self:hasRemainingAmmoToEngageMissiles(numOfHarms))) - self.iads:printOutputToLog("PD enough missiles: "..tostring(self:pointDefencesHaveRemainingAmmo(numOfHarms))) - self.iads:printOutputToLog("PD enough launchers: "..tostring(self:pointDefencesHaveEnoughLaunchers(numOfHarms))) - --]] - return ( ((self:hasEnoughLaunchersToEngageMissiles(numOfHarms) and self:hasRemainingAmmoToEngageMissiles(numOfHarms) and self:getCanEngageHARM()) or (self:pointDefencesHaveRemainingAmmo(numOfHarms) and self:pointDefencesHaveEnoughLaunchers(numOfHarms)))) -end - -function SkynetIADSAbstractRadarElement:informOfHARM(harmContact) - local radars = self:getRadars() - for j = 1, #radars do - local radar = radars[j] - local distanceNM = mist.utils.metersToNM(self:getDistanceInMetersToContact(radar, harmContact:getPosition().p)) - local harmToSAMHeading = mist.utils.toDegree(mist.utils.getHeadingPoints(harmContact:getPosition().p, radar:getPosition().p)) - local harmToSAMAspect = self:calculateAspectInDegrees(harmContact:getMagneticHeading(), harmToSAMHeading) - local speedKT = harmContact:getGroundSpeedInKnots(0) - local secondsToImpact = self:getSecondsToImpact(distanceNM, speedKT) - --TODO: use tti instead of distanceNM? - -- when iterating through the radars, store shortest tti and work with that value?? - if ( harmToSAMAspect < SkynetIADSAbstractRadarElement.HARM_TO_SAM_ASPECT and distanceNM < SkynetIADSAbstractRadarElement.HARM_LOOKAHEAD_NM ) then - self:addObjectIdentifiedAsHARM(harmContact) - if ( #self:getPointDefences() > 0 and self:pointDefencesGoLive() == true and self.iads:getDebugSettings().harmDefence ) then - self.iads:printOutputToLog("POINT DEFENCES GOING LIVE FOR: "..self:getDCSName().." | TTI: "..secondsToImpact) - end - --self.iads:printOutputToLog("Ignore HARM shutdown: "..tostring(self:shallIgnoreHARMShutdown())) - if ( self:getIsAPointDefence() == false and ( self:isDefendingHARM() == false or ( self:getHARMShutdownTime() < secondsToImpact ) ) and self:shallIgnoreHARMShutdown() == false) then - self:goSilentToEvadeHARM(secondsToImpact) - break - end - end - end -end - -function SkynetIADSAbstractElement:addObjectIdentifiedAsHARM(harmContact) - self:insertToTableIfNotAlreadyAdded(self.objectsIdentifiedAsHarms, harmContact) -end - -function SkynetIADSAbstractRadarElement:calculateAspectInDegrees(harmHeading, harmToSAMHeading) - local aspect = harmHeading - harmToSAMHeading - if ( aspect < 0 ) then - aspect = -1 * aspect - end - if aspect > 180 then - aspect = 360 - aspect - end - return mist.utils.round(aspect) -end - -function SkynetIADSAbstractRadarElement:getNumberOfObjectsItentifiedAsHARMS() - return #self.objectsIdentifiedAsHarms -end - -function SkynetIADSAbstractRadarElement:cleanUpOldObjectsIdentifiedAsHARMS() - local newHARMS = {} - for i = 1, #self.objectsIdentifiedAsHarms do - local harmContact = self.objectsIdentifiedAsHarms[i] - if harmContact:getAge() < self.objectsIdentifiedAsHarmsMaxTargetAge then - table.insert(newHARMS, harmContact) - end - end - --stop point defences acting as ew (always on), will occur if activated via evaluateIfTargetsContainHARMs() - --if in this iteration all harms where cleared we turn of the point defence. But in any other cases we dont turn of point defences, that interferes with other parts of the iads - -- when setting up the iads (letting pds go to read state) - if (#newHARMS == 0 and self:getNumberOfObjectsItentifiedAsHARMS() > 0 ) then - self:pointDefencesStopActingAsEW() - end - self.objectsIdentifiedAsHarms = newHARMS -end - - -function SkynetIADSAbstractRadarElement.evaluateIfTargetsContainHARMs(self) - - --if an emitter dies the SAM site being jammed will revert back to normal operation: - if self.lastJammerUpdate > 0 and ( timer:getTime() - self.lastJammerUpdate ) > 10 then - self:jam(0) - self.lastJammerUpdate = 0 - end - - --we use the regular interval of this method to update to other states: - self:updateMissilesInFlight() - self:cleanUpOldObjectsIdentifiedAsHARMS() -end - -end -do ---this class is currently used for AWACS and Ships, at a latter date a separate class for ships could be created, currently not needed -SkynetIADSAWACSRadar = {} -SkynetIADSAWACSRadar = inheritsFrom(SkynetIADSAbstractRadarElement) - -function SkynetIADSAWACSRadar:create(radarUnit, iads) - local instance = self:superClass():create(radarUnit, iads) - setmetatable(instance, self) - self.__index = self - instance.lastUpdatePosition = nil - instance.natoName = radarUnit:getTypeName() - return instance -end - -function SkynetIADSAWACSRadar:setupElements() - local unit = self:getDCSRepresentation() - local radar = SkynetIADSSAMSearchRadar:create(unit) - radar:setupRangeData() - table.insert(self.searchRadars, radar) -end - - --- AWACs will not scan for HARMS -function SkynetIADSAWACSRadar:scanForHarms() - -end - -function SkynetIADSAWACSRadar:getMaxAllowedMovementForAutonomousUpdateInNM() - --local radarRange = mist.utils.metersToNM(self.searchRadars[1]:getMaxRangeFindingTarget()) - --return mist.utils.round(radarRange / 10) - --fixed to 10 nm miles to better fit small SAM sites - return 10 -end - -function SkynetIADSAWACSRadar:isUpdateOfAutonomousStateOfSAMSitesRequired() - local isUpdateRequired = self:getDistanceTraveledSinceLastUpdate() > self:getMaxAllowedMovementForAutonomousUpdateInNM() - if isUpdateRequired then - self.lastUpdatePosition = nil - end - return isUpdateRequired -end - -function SkynetIADSAWACSRadar:getDistanceTraveledSinceLastUpdate() - local currentPosition = nil - if self.lastUpdatePosition == nil and self:getDCSRepresentation():isExist() then - self.lastUpdatePosition = self:getDCSRepresentation():getPosition().p - end - if self:getDCSRepresentation():isExist() then - currentPosition = self:getDCSRepresentation():getPosition().p - end - return mist.utils.round(mist.utils.metersToNM(self:getDistanceToUnit(self.lastUpdatePosition, currentPosition))) -end - -end - -do -SkynetIADSCommandCenter = {} -SkynetIADSCommandCenter = inheritsFrom(SkynetIADSAbstractRadarElement) - -function SkynetIADSCommandCenter:create(commandCenter, iads) - local instance = self:superClass():create(commandCenter, iads) - setmetatable(instance, self) - self.__index = self - instance.natoName = "COMMAND CENTER" - return instance -end - -function SkynetIADSCommandCenter:goDark() - -end - -function SkynetIADSCommandCenter:goLive() - -end - -end -do - -SkynetIADSContact = {} -SkynetIADSContact = inheritsFrom(SkynetIADSAbstractDCSObjectWrapper) - -SkynetIADSContact.CLIMB = "CLIMB" -SkynetIADSContact.DESCEND = "DESCEND" - -SkynetIADSContact.HARM = "HARM" -SkynetIADSContact.NOT_HARM = "NOT_HARM" -SkynetIADSContact.HARM_UNKNOWN = "HARM_UNKNOWN" - -function SkynetIADSContact:create(dcsRadarTarget, abstractRadarElementDetected) - local instance = self:superClass():create(dcsRadarTarget.object) - setmetatable(instance, self) - self.__index = self - instance.abstractRadarElementsDetected = {} - table.insert(instance.abstractRadarElementsDetected, abstractRadarElementDetected) - instance.firstContactTime = timer.getAbsTime() - instance.lastTimeSeen = 0 - instance.dcsRadarTarget = dcsRadarTarget - instance.position = instance:getDCSRepresentation():getPosition() - instance.numOfTimesRefreshed = 0 - instance.speed = 0 - instance.harmState = SkynetIADSContact.HARM_UNKNOWN - instance.simpleAltitudeProfile = {} - return instance -end - -function SkynetIADSContact:setHARMState(state) - self.harmState = state -end - -function SkynetIADSContact:getHARMState() - return self.harmState -end - -function SkynetIADSContact:isIdentifiedAsHARM() - return self.harmState == SkynetIADSContact.HARM -end - -function SkynetIADSContact:isHARMStateUnknown() - return self.harmState == SkynetIADSContact.HARM_UNKNOWN -end - -function SkynetIADSContact:getMagneticHeading() - if ( self:isExist() ) then - return mist.utils.round(mist.utils.toDegree(mist.getHeading(self:getDCSRepresentation()))) - else - return -1 - end -end - -function SkynetIADSContact:getAbstractRadarElementsDetected() - return self.abstractRadarElementsDetected -end - -function SkynetIADSContact:addAbstractRadarElementDetected(radar) - self:insertToTableIfNotAlreadyAdded(self.abstractRadarElementsDetected, radar) -end - -function SkynetIADSContact:isTypeKnown() - return self.dcsRadarTarget.type -end - -function SkynetIADSContact:isDistanceKnown() - return self.dcsRadarTarget.distance -end - -function SkynetIADSContact:getTypeName() - if self:isIdentifiedAsHARM() then - return SkynetIADSContact.HARM - end - local category = self:getDCSRepresentation():getCategory() - if category == Object.Category.UNIT then - return self.typeName - end - return "UNKNOWN" -end - -function SkynetIADSContact:getPosition() - return self.position -end - -function SkynetIADSContact:getGroundSpeedInKnots(decimals) - if decimals == nil then - decimals = 2 - end - return mist.utils.round(self.speed, decimals) -end - -function SkynetIADSContact:getHeightInFeetMSL() - if self:isExist() then - return mist.utils.round(mist.utils.metersToFeet(self:getDCSRepresentation():getPosition().p.y), 0) - else - return 0 - end -end - -function SkynetIADSContact:getDesc() - if self:isExist() then - return self:getDCSRepresentation():getDesc() - else - return {} - end -end - -function SkynetIADSContact:getNumberOfTimesHitByRadar() - return self.numOfTimesRefreshed -end - -function SkynetIADSContact:refresh() - if self:isExist() then - local timeDelta = (timer.getAbsTime() - self.lastTimeSeen) - if timeDelta > 0 then - self.numOfTimesRefreshed = self.numOfTimesRefreshed + 1 - local distance = mist.utils.metersToNM(mist.utils.get2DDist(self.position.p, self:getDCSRepresentation():getPosition().p)) - local hours = timeDelta / 3600 - self.speed = (distance / hours) - self:updateSimpleAltitudeProfile() - self.position = self:getDCSRepresentation():getPosition() - end - end - self.lastTimeSeen = timer.getAbsTime() -end - -function SkynetIADSContact:updateSimpleAltitudeProfile() - local currentAltitude = self:getDCSRepresentation():getPosition().p.y - - local previousPath = "" - if #self.simpleAltitudeProfile > 0 then - previousPath = self.simpleAltitudeProfile[#self.simpleAltitudeProfile] - end - - if self.position.p.y > currentAltitude and previousPath ~= SkynetIADSContact.DESCEND then - table.insert(self.simpleAltitudeProfile, SkynetIADSContact.DESCEND) - elseif self.position.p.y < currentAltitude and previousPath ~= SkynetIADSContact.CLIMB then - table.insert(self.simpleAltitudeProfile, SkynetIADSContact.CLIMB) - end -end - -function SkynetIADSContact:getSimpleAltitudeProfile() - return self.simpleAltitudeProfile -end - -function SkynetIADSContact:getAge() - return mist.utils.round(timer.getAbsTime() - self.lastTimeSeen) -end - -end - -do - -SkynetIADSEWRadar = {} -SkynetIADSEWRadar = inheritsFrom(SkynetIADSAbstractRadarElement) - -function SkynetIADSEWRadar:create(radarUnit, iads) - local instance = self:superClass():create(radarUnit, iads) - setmetatable(instance, self) - self.__index = self - instance.autonomousBehaviour = SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DARK - return instance -end - -function SkynetIADSEWRadar:setupElements() - local unit = self:getDCSRepresentation() - local unitType = unit:getTypeName() - for typeName, dataType in pairs(SkynetIADS.database) do - for entry, unitData in pairs(dataType) do - if entry == 'searchRadar' then - --buildSingleUnit checks to make sure the EW radar is defined in the Skynet database. If it is not, self.searchRadars will be 0 so no ew radar will be added - self:buildSingleUnit(unit, SkynetIADSSAMSearchRadar, self.searchRadars, unitData) - if #self.searchRadars > 0 then - local harmDetection = dataType['harm_detection_chance'] - self:setHARMDetectionChance(harmDetection) - if unitData[unitType]['name'] then - local natoName = unitData[unitType]['name']['NATO'] - self:buildNatoName(natoName) - end - return - end - end - end - end -end - ---an Early Warning Radar has simplified check to determine if its autonomous or not -function SkynetIADSEWRadar:setToCorrectAutonomousState() - if self:hasActiveConnectionNode() and self:hasWorkingPowerSource() and self.iads:isCommandCenterUsable() then - self:resetAutonomousState() - self:goLive() - end - if self:hasActiveConnectionNode() == false or self.iads:isCommandCenterUsable() == false then - self:goAutonomous() - end -end - -end -do - -SkynetIADSJammer = {} -SkynetIADSJammer.__index = SkynetIADSJammer - -function SkynetIADSJammer:create(emitter, iads) - local jammer = {} - setmetatable(jammer, SkynetIADSJammer) - jammer.radioMenu = nil - jammer.emitter = emitter - jammer.jammerTaskID = nil - jammer.iads = {iads} - jammer.maximumEffectiveDistanceNM = 200 - --jammer probability settings are stored here, visualisation, see: https://docs.google.com/spreadsheets/d/16rnaU49ZpOczPEsdGJ6nfD0SLPxYLEYKmmo4i2Vfoe0/edit#gid=0 - jammer.jammerTable = { - ['SA-2'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.4 ^ distanceNauticalMiles ) + 90 end, - ['canjam'] = true, - }, - ['SA-3'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.4 ^ distanceNauticalMiles ) + 80 end, - ['canjam'] = true, - }, - ['SA-6'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.4 ^ distanceNauticalMiles ) + 23 end, - ['canjam'] = true, - }, - ['SA-8'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.35 ^ distanceNauticalMiles ) + 30 end, - ['canjam'] = true, - }, - ['SA-10'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.07 ^ (distanceNauticalMiles / 1.13) ) + 5 end, - ['canjam'] = true, - }, - ['SA-11'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.25 ^ distanceNauticalMiles ) + 15 end, - ['canjam'] = true, - }, - ['SA-15'] = { - ['function'] = function(distanceNauticalMiles) return ( 1.15 ^ distanceNauticalMiles ) + 5 end, - ['canjam'] = true, - }, - } - return jammer -end - -function SkynetIADSJammer:masterArmOn() - self:masterArmSafe() - self.jammerTaskID = mist.scheduleFunction(SkynetIADSJammer.runCycle, {self}, 1, 10) -end - -function SkynetIADSJammer:addFunction(natoName, jammerFunction) - self.jammerTable[natoName] = { - ['function'] = jammerFunction, - ['canjam'] = true - } -end - -function SkynetIADSJammer:setMaximumEffectiveDistance(distance) - self.maximumEffectiveDistanceNM = distance -end - -function SkynetIADSJammer:disableFor(natoName) - self.jammerTable[natoName]['canjam'] = false -end - -function SkynetIADSJammer:isKnownRadarEmitter(natoName) - local isActive = false - for unitName, unit in pairs(self.jammerTable) do - if unitName == natoName and unit['canjam'] == true then - isActive = true - end - end - return isActive -end - -function SkynetIADSJammer:addIADS(iads) - table.insert(self.iads, iads) -end - -function SkynetIADSJammer:getSuccessProbability(distanceNauticalMiles, natoName) - local probability = 0 - local jammerSettings = self.jammerTable[natoName] - if jammerSettings ~= nil then - probability = jammerSettings['function'](distanceNauticalMiles) - end - return probability -end - -function SkynetIADSJammer:getDistanceNMToRadarUnit(radarUnit) - return mist.utils.metersToNM(mist.utils.get3DDist(self.emitter:getPosition().p, radarUnit:getPosition().p)) -end - -function SkynetIADSJammer.runCycle(self) - - if self.emitter:isExist() == false then - self:masterArmSafe() - return - end - - for i = 1, #self.iads do - local iads = self.iads[i] - local samSites = iads:getActiveSAMSites() - for j = 1, #samSites do - local samSite = samSites[j] - local radars = samSite:getRadars() - local hasLOS = false - local distance = 0 - local natoName = samSite:getNatoName() - for l = 1, #radars do - local radar = radars[l] - distance = self:getDistanceNMToRadarUnit(radar) - -- I try to emulate the system as it would work in real life, so a jammer can only jam a SAM site if has line of sight to at least one radar in the group - if self:isKnownRadarEmitter(natoName) and self:hasLineOfSightToRadar(radar) and distance <= self.maximumEffectiveDistanceNM then - if iads:getDebugSettings().jammerProbability then - iads:printOutput("JAMMER: Distance: "..distance) - end - samSite:jam(self:getSuccessProbability(distance, natoName)) - end - end - end - end -end - -function SkynetIADSJammer:hasLineOfSightToRadar(radar) - local radarPos = radar:getPosition().p - --lift the radar 30 meters off the ground, some 3d models are dug in to the ground, creating issues in calculating LOS - radarPos.y = radarPos.y + 30 - return land.isVisible(radarPos, self.emitter:getPosition().p) -end - -function SkynetIADSJammer:masterArmSafe() - mist.removeFunction(self.jammerTaskID) -end - ---TODO: Remove Menu when emitter dies: -function SkynetIADSJammer:addRadioMenu() - self.radioMenu = missionCommands.addSubMenu('Jammer: '..self.emitter:getName()) - missionCommands.addCommand('Master Arm On', self.radioMenu, SkynetIADSJammer.updateMasterArm, {self = self, option = 'masterArmOn'}) - missionCommands.addCommand('Master Arm Safe', self.radioMenu, SkynetIADSJammer.updateMasterArm, {self = self, option = 'masterArmSafe'}) -end - -function SkynetIADSJammer.updateMasterArm(params) - local option = params.option - local self = params.self - if option == 'masterArmOn' then - self:masterArmOn() - elseif option == 'masterArmSafe' then - self:masterArmSafe() - end -end - -function SkynetIADSJammer:removeRadioMenu() - missionCommands.removeItem(self.radioMenu) -end - -end -do - -SkynetIADSSAMSearchRadar = {} -SkynetIADSSAMSearchRadar = inheritsFrom(SkynetIADSAbstractDCSObjectWrapper) - -function SkynetIADSSAMSearchRadar:create(unit) - local instance = self:superClass():create(unit) - setmetatable(instance, self) - self.__index = self - instance.firingRangePercent = 100 - instance.maximumRange = 0 - instance.initialNumberOfMissiles = 0 - instance.remainingNumberOfMissiles = 0 - instance.initialNumberOfShells = 0 - instance.remainingNumberOfShells = 0 - instance.triedSensors = 0 - return instance -end - ---override in subclasses to match different datastructure of getSensors() -function SkynetIADSSAMSearchRadar:setupRangeData() - if self:isExist() then - local data = self:getDCSRepresentation():getSensors() - if data == nil then - --this is to prevent infinite calls between launcher and search radar - self.triedSensors = self.triedSensors + 1 - --the SA-13 does not have any sensor data, but is has launcher data, so we use the stuff from the launcher for the radar range. - SkynetIADSSAMLauncher.setupRangeData(self) - return - end - for i = 1, #data do - local subEntries = data[i] - for j = 1, #subEntries do - local sensorInformation = subEntries[j] - -- some sam sites have IR and passive EWR detection, we are just interested in the radar data - -- investigate if upperHemisphere and headOn is ok, I guess it will work for most detection cases - if sensorInformation.type == Unit.SensorType.RADAR and sensorInformation['detectionDistanceAir'] then - local upperHemisphere = sensorInformation['detectionDistanceAir']['upperHemisphere']['headOn'] - local lowerHemisphere = sensorInformation['detectionDistanceAir']['lowerHemisphere']['headOn'] - self.maximumRange = upperHemisphere - if lowerHemisphere > upperHemisphere then - self.maximumRange = lowerHemisphere - end - end - end - end - end -end - -function SkynetIADSSAMSearchRadar:getMaxRangeFindingTarget() - return self.maximumRange -end - -function SkynetIADSSAMSearchRadar:isRadarWorking() - -- the ammo check is for the SA-13 which does not return any sensor data: - return (self:isExist() == true and ( self:getDCSRepresentation():getSensors() ~= nil or self:getDCSRepresentation():getAmmo() ~= nil ) ) -end - -function SkynetIADSSAMSearchRadar:setFiringRangePercent(percent) - self.firingRangePercent = percent -end - -function SkynetIADSSAMSearchRadar:getDistance(target) - return mist.utils.get2DDist(target:getPosition().p, self:getDCSRepresentation():getPosition().p) -end - -function SkynetIADSSAMSearchRadar:getHeight(target) - local radarElevation = self:getDCSRepresentation():getPosition().p.y - local targetElevation = target:getPosition().p.y - return math.abs(targetElevation - radarElevation) -end - -function SkynetIADSSAMSearchRadar:isInHorizontalRange(target) - return (self:getMaxRangeFindingTarget() / 100 * self.firingRangePercent) >= self:getDistance(target) -end - -function SkynetIADSSAMSearchRadar:isInRange(target) - if self:isExist() == false then - return false - end - return self:isInHorizontalRange(target) -end - -end - -do - -SkynetIADSSamSite = {} -SkynetIADSSamSite = inheritsFrom(SkynetIADSAbstractRadarElement) - -function SkynetIADSSamSite:create(samGroup, iads) - local sam = self:superClass():create(samGroup, iads) - setmetatable(sam, self) - self.__index = self - sam.targetsInRange = false - sam.goLiveConstraints = {} - return sam -end - -function SkynetIADSSamSite:addGoLiveConstraint(constraintName, constraint) - self.goLiveConstraints[constraintName] = constraint -end - -function SkynetIADSAbstractRadarElement:areGoLiveConstraintsSatisfied(contact) - for constraintName, constraint in pairs(self.goLiveConstraints) do - if ( constraint(contact) ~= true ) then - return false - end - end - return true -end - -function SkynetIADSSamSite:isDestroyed() - local isDestroyed = true - for i = 1, #self.launchers do - local launcher = self.launchers[i] - if launcher:isExist() == true then - isDestroyed = false - end - end - local radars = self:getRadars() - for i = 1, #radars do - local radar = radars[i] - if radar:isExist() == true then - isDestroyed = false - end - end - return isDestroyed -end - -function SkynetIADSSamSite:targetCycleUpdateStart() - self.targetsInRange = false -end - -function SkynetIADSSamSite:targetCycleUpdateEnd() - if self.targetsInRange == false and self.actAsEW == false and self:getAutonomousState() == false and self:getAutonomousBehaviour() == SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI then - self:goDark() - end -end - -function SkynetIADSSamSite:informOfContact(contact) - -- we make sure isTargetInRange (expensive call) is only triggered if no previous calls to this method resulted in targets in range - if ( self.targetsInRange == false and self:areGoLiveConstraintsSatisfied(contact) == true and self:isTargetInRange(contact) and ( contact:isIdentifiedAsHARM() == false or ( contact:isIdentifiedAsHARM() == true and self:getCanEngageHARM() == true ) ) ) then - self:goLive() - self.targetsInRange = true - end -end - -end -do - -SkynetIADSSAMTrackingRadar = {} -SkynetIADSSAMTrackingRadar = inheritsFrom(SkynetIADSSAMSearchRadar) - -function SkynetIADSSAMTrackingRadar:create(unit) - local instance = self:superClass():create(unit) - setmetatable(instance, self) - self.__index = self - return instance -end - -end -do - -SkynetIADSSAMLauncher = {} -SkynetIADSSAMLauncher = inheritsFrom(SkynetIADSSAMSearchRadar) - -function SkynetIADSSAMLauncher:create(unit) - local instance = self:superClass():create(unit) - setmetatable(instance, self) - self.__index = self - instance.maximumFiringAltitude = 0 - return instance -end - -function SkynetIADSSAMLauncher:setupRangeData() - self.remainingNumberOfMissiles = 0 - self.remainingNumberOfShells = 0 - if self:isExist() then - local data = self:getDCSRepresentation():getAmmo() - local initialNumberOfMissiles = 0 - local initialNumberOfShells = 0 - --data becomes nil, when all missiles are fired - if data then - for i = 1, #data do - local ammo = data[i] - --we ignore checks on radar guidance types, since we are not interested in how exactly the missile is guided by the SAM site. - if ammo.desc.category == Weapon.Category.MISSILE then - --TODO: see what the difference is between Max and Min values, SA-3 has higher Min value than Max?, most likely it has to do with the box parameters supplied by launcher - --to simplyfy we just use the larger value, sam sites need a few seconds of tracking time to fire, by that time contact has most likely closed in on the SAM site. - local altMin = ammo.desc.rangeMaxAltMin - local altMax = ammo.desc.rangeMaxAltMax - self.maximumRange = altMin - if altMin < altMax then - self.maximumRange = altMax - end - self.maximumFiringAltitude = ammo.desc.altMax - self.remainingNumberOfMissiles = self.remainingNumberOfMissiles + ammo.count - initialNumberOfMissiles = self.remainingNumberOfMissiles - end - if ammo.desc.category == Weapon.Category.SHELL then - self.remainingNumberOfShells = self.remainingNumberOfShells + ammo.count - initialNumberOfShells = self.remainingNumberOfShells - end - --if no distance was detected we run the code for the search radar. This happens when all in one units are passed like the shilka - if self.maximumRange == 0 then - --this is to prevent infinite calls between launcher and search radar - if self.triedSensors <= 2 then - SkynetIADSSAMSearchRadar.setupRangeData(self) - end - end - end - -- conditions here are because setupRangeData() is called multiple times in the code to update ammo status, we set initial values only the first time the method is called - if self.initialNumberOfMissiles == 0 then - self.initialNumberOfMissiles = initialNumberOfMissiles - end - if self.initialNumberOfShells == 0 then - self.initialNumberOfShells = initialNumberOfShells - end - end - end -end - -function SkynetIADSSAMLauncher:getInitialNumberOfShells() - return self.initialNumberOfShells -end - -function SkynetIADSSAMLauncher:getRemainingNumberOfShells() - self:setupRangeData() - return self.remainingNumberOfShells -end - -function SkynetIADSSAMLauncher:getInitialNumberOfMissiles() - return self.initialNumberOfMissiles -end - -function SkynetIADSSAMLauncher:getRemainingNumberOfMissiles() - self:setupRangeData() - return self.remainingNumberOfMissiles -end - -function SkynetIADSSAMLauncher:getRange() - return self.maximumRange -end - -function SkynetIADSSAMLauncher:getMaximumFiringAltitude() - return self.maximumFiringAltitude -end - -function SkynetIADSSAMLauncher:isWithinFiringHeight(target) - -- if no max firing height is set (radar quided AAA) then we use the vertical range, bit of a hack but probably ok for AAA - if self:getMaximumFiringAltitude() > 0 then - return self:getMaximumFiringAltitude() >= self:getHeight(target) - else - return self:getRange() >= self:getHeight(target) - end -end - -function SkynetIADSSAMLauncher:isInRange(target) - if self:isExist() == false then - return false - end - return self:isWithinFiringHeight(target) and self:isInHorizontalRange(target) -end - -end - ---[[ -SA-2 Launcher: - { - count=1, - desc={ - Nmax=17, - RCS=0.39669999480247, - _origin="", - altMax=25000, - altMin=100, - box={ - max={x=4.7303376197815, y=0.84564626216888, z=0.84564626216888}, - min={x=-5.8387970924377, y=-0.84564626216888, z=-0.84564626216888} - }, - category=1, - displayName="SA2V755", - fuseDist=20, - guidance=4, - life=2, - missileCategory=2, - rangeMaxAltMax=30000, - rangeMaxAltMin=40000, - rangeMin=7000, - typeName="SA2V755", - warhead={caliber=500, explosiveMass=196, mass=196, type=1} - } - } -} ---]] -do - -SkynetIADSHARMDetection = {} -SkynetIADSHARMDetection.__index = SkynetIADSHARMDetection - -SkynetIADSHARMDetection.HARM_THRESHOLD_SPEED_KTS = 800 - -function SkynetIADSHARMDetection:create(iads) - local harmDetection = {} - setmetatable(harmDetection, self) - harmDetection.contacts = {} - harmDetection.iads = iads - harmDetection.contactRadarsEvaluated = {} - return harmDetection -end - -function SkynetIADSHARMDetection:setContacts(contacts) - self.contacts = contacts -end - -function SkynetIADSHARMDetection:evaluateContacts() - self:cleanAgedContacts() - for i = 1, #self.contacts do - local contact = self.contacts[i] - local groundSpeed = contact:getGroundSpeedInKnots(0) - --if a contact has only been hit by a radar once it's speed is 0 - if groundSpeed == 0 then - return - end - local simpleAltitudeProfile = contact:getSimpleAltitudeProfile() - local newRadarsToEvaluate = self:getNewRadarsThatHaveDetectedContact(contact) - --self.iads:printOutputToLog(contact:getName().." new Radars to evaluate: "..#newRadarsToEvaluate) - --self.iads:printOutputToLog(contact:getName().." ground speed: "..groundSpeed) - if ( #newRadarsToEvaluate > 0 and contact:isIdentifiedAsHARM() == false and ( groundSpeed > SkynetIADSHARMDetection.HARM_THRESHOLD_SPEED_KTS and #simpleAltitudeProfile <= 2 ) ) then - local detectionProbability = self:getDetectionProbability(newRadarsToEvaluate) - --self.iads:printOutputToLog("DETECTION PROB: "..detectionProbability) - if ( self:shallReactToHARM(detectionProbability) ) then - contact:setHARMState(SkynetIADSContact.HARM) - if (self.iads:getDebugSettings().harmDefence ) then - self.iads:printOutputToLog("HARM IDENTIFIED: "..contact:getTypeName().." | DETECTION PROBABILITY WAS: "..detectionProbability.."%") - end - else - contact:setHARMState(SkynetIADSContact.NOT_HARM) - if (self.iads:getDebugSettings().harmDefence ) then - self.iads:printOutputToLog("HARM NOT IDENTIFIED: "..contact:getTypeName().." | DETECTION PROBABILITY WAS: "..detectionProbability.."%") - end - end - end - - if ( #simpleAltitudeProfile > 2 and contact:isIdentifiedAsHARM() ) then - contact:setHARMState(SkynetIADSContact.HARM_UNKNOWN) - if (self.iads:getDebugSettings().harmDefence ) then - self.iads:printOutputToLog("CORRECTING HARM STATE: CONTACT IS NOT A HARM: "..contact:getName()) - end - end - - if ( contact:isIdentifiedAsHARM() ) then - self:informRadarsOfHARM(contact) - end - end -end - -function SkynetIADSHARMDetection:cleanAgedContacts() - local activeContactRadars = {} - for contact, radars in pairs (self.contactRadarsEvaluated) do - if contact:getAge() < 32 then - activeContactRadars[contact] = radars - end - end - self.contactRadarsEvaluated = activeContactRadars -end - -function SkynetIADSHARMDetection:getNewRadarsThatHaveDetectedContact(contact) - local newRadars = contact:getAbstractRadarElementsDetected() - local radars = self.contactRadarsEvaluated[contact] - if radars then - newRadars = {} - local contactRadars = contact:getAbstractRadarElementsDetected() - for i = 1, #contactRadars do - local contactRadar = contactRadars[i] - local newRadar = self:isElementInTable(radars, contactRadar) - if newRadar ~= nil then - table.insert(newRadars, newRadar) - end - end - end - self.contactRadarsEvaluated[contact] = contact:getAbstractRadarElementsDetected() - return newRadars -end - -function SkynetIADSHARMDetection:isElementInTable(tbl, element) - for i = 1, #tbl do - tblElement = tbl[i] - if tblElement == element then - return nil - end - end - return element -end - -function SkynetIADSHARMDetection:informRadarsOfHARM(contact) - local samSites = self.iads:getUsableSAMSites() - self:updateRadarsOfSites(samSites, contact) - - local ewRadars = self.iads:getUsableEarlyWarningRadars() - self:updateRadarsOfSites(ewRadars, contact) -end - -function SkynetIADSHARMDetection:updateRadarsOfSites(sites, contact) - for i = 1, #sites do - local site = sites[i] - site:informOfHARM(contact) - end -end - -function SkynetIADSHARMDetection:shallReactToHARM(chance) - return chance >= math.random(1, 100) -end - -function SkynetIADSHARMDetection:getDetectionProbability(radars) - local detectionChance = 0 - local missChance = 100 - local detection = 0 - for i = 1, #radars do - detection = radars[i]:getHARMDetectionChance() - if ( detectionChance == 0 ) then - detectionChance = detection - else - detectionChance = detectionChance + (detection * (missChance / 100)) - end - missChance = 100 - detection - end - return detectionChance -end - -end - - diff --git a/resources/plugins/skynetiads/skynetiads-config.lua b/resources/plugins/skynetiads/skynetiads-config.lua deleted file mode 100644 index ba7317e56..000000000 --- a/resources/plugins/skynetiads/skynetiads-config.lua +++ /dev/null @@ -1,204 +0,0 @@ -------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Mission configuration file for the Skynet-IADS framework --- see https://github.com/walder/Skynet-IADS --- --- This configuration is tailored for a mission generated by DCS Liberation --- see https://github.com/dcs-liberation/dcs_liberation -------------------------------------------------------------------------------------------------------------------------------------------------------------- - --- Skynet-IADS plugin - configuration -env.info("DCSLiberation|Skynet-IADS plugin - configuration") - -if dcsLiberation and SkynetIADS then - - -- specific options - local createRedIADS = false - local createBlueIADS = false - local includeRedInRadio = false - local includeBlueInRadio = false - local debugRED = false - local debugBLUE = false - - -- retrieve specific options values - if dcsLiberation.plugins then - if dcsLiberation.plugins.skynetiads then - createRedIADS = dcsLiberation.plugins.skynetiads.createRedIADS - createBlueIADS = dcsLiberation.plugins.skynetiads.createBlueIADS - includeRedInRadio = dcsLiberation.plugins.skynetiads.includeRedInRadio - includeBlueInRadio = dcsLiberation.plugins.skynetiads.includeBlueInRadio - debugRED = dcsLiberation.plugins.skynetiads.debugRED - debugBLUE = dcsLiberation.plugins.skynetiads.debugBLUE - end - end - - env.info(string.format("DCSLiberation|Skynet-IADS plugin - createRedIADS=%s", tostring(createRedIADS))) - env.info(string.format("DCSLiberation|Skynet-IADS plugin - createBlueIADS=%s", tostring(createBlueIADS))) - env.info(string.format("DCSLiberation|Skynet-IADS plugin - includeRedInRadio=%s", tostring(includeRedInRadio))) - env.info(string.format("DCSLiberation|Skynet-IADS plugin - includeBlueInRadio=%s", tostring(includeBlueInRadio))) - env.info(string.format("DCSLiberation|Skynet-IADS plugin - debugRED=%s", tostring(debugRED))) - env.info(string.format("DCSLiberation|Skynet-IADS plugin - debugBLUE=%s", tostring(debugBLUE))) - - -- actual configuration code - local function initializeIADSElement(iads, iads_unit, element) - if iads_unit == nil then - -- skip processing of units which can not be handled by skynet - return - end - if element.engagement_zone then - iads_unit:setEngagementZone(element.engagement_zone) - end - if element.can_engage_harm then - iads_unit:setCanEngageHARM(element.can_engage_harm) - end - if element.harm_detection_chance then - iads_unit:setHARMDetectionChance(tonumber(element.harm_detection_chance)) - end - if element.can_engage_air_weapon then - iads_unit:setCanEngageAirWeapons(element.can_engage_air_weapon) - end - if element.go_live_range_in_percent then - iads_unit:setGoLiveRangeInPercent(tonumber(element.go_live_range_in_percent)) - end - if element.autonomous_behaviour then - iads_unit:setAutonomousBehaviour(element.autonomous_behaviour) - end - if element.ConnectionNode then - for i, cn in pairs(element.ConnectionNode) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - adding IADS ConnectionNode %s", cn)) - local connection_node = StaticObject.getByName(cn .. " object") -- pydcs adds ' object' to the unit name for static elements - if connection_node then - iads_unit:addConnectionNode(connection_node) - end - end - end - if element.PowerSource then - for i, ps in pairs(element.PowerSource) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - adding IADS PowerSource %s", ps)) - local power_source = StaticObject.getByName(ps .. " object") -- pydcs adds ' object' to the unit name for static elements - if power_source then - iads_unit:addPowerSource(power_source) - end - end - end - if element.PD then - for i, pd in pairs(element.PD) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - adding IADS Point Defence %s", pd)) - local point_defence = iads:addSAMSite(pd) - if point_defence ~= nil then - -- only add as point defence if skynet can handle the PD unit - iads_unit:addPointDefence(point_defence) - end - end - end - end - - local function initializeIADS(iads, coalition, inRadio, debug) - - local coalitionPrefix = "BLUE" - if coalition == 1 then - coalitionPrefix = "RED" - end - - if debug then - env.info("adding debug information") - local iadsDebug = iads:getDebugSettings() - iadsDebug.IADSStatus = true - iadsDebug.samWentDark = true - iadsDebug.contacts = true - iadsDebug.radarWentLive = true - iadsDebug.noWorkingCommmandCenter = true - iadsDebug.ewRadarNoConnection = true - iadsDebug.samNoConnection = true - iadsDebug.jammerProbability = true - iadsDebug.addedEWRadar = true - iadsDebug.hasNoPower = true - iadsDebug.harmDefence = true - iadsDebug.samSiteStatusEnvOutput = true - iadsDebug.earlyWarningRadarStatusEnvOutput = true - iadsDebug.commandCenterStatusEnvOutput = true - end - - -- add the AWACS - if dcsLiberation.AWACs then - for _, data in pairs(dcsLiberation.AWACs) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - processing AWACS %s", data.dcsGroupName)) - local group = Group.getByName(data.dcsGroupName) - if group then - if group:getCoalition() == coalition then - local unit = group:getUnit(1) - if unit then - local unitName = unit:getName() - env.info(string.format("DCSLiberation|Skynet-IADS plugin - adding AWACS %s", unitName)) - iads:addEarlyWarningRadar(unitName) - end - end - end - end - end - - -- add the IADS Elements: SAM, EWR, and Command Centers - if dcsLiberation.IADS then - local coalition_iads = dcsLiberation.IADS[coalitionPrefix] - if coalition_iads.Ewr then - for _, unit in pairs(coalition_iads.Ewr) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - processing IADS EWR %s", unit.dcsGroupName)) - local iads_unit = iads:addEarlyWarningRadar(unit.dcsGroupName) - initializeIADSElement(iads, iads_unit, unit) - end - end - if coalition_iads.Sam then - for _, unit in pairs(coalition_iads.Sam) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - processing IADS SAM %s", unit.dcsGroupName)) - local iads_unit = iads:addSAMSite(unit.dcsGroupName) - initializeIADSElement(iads, iads_unit, unit) - end - end - if coalition_iads.SamAsEwr then - for _, unit in pairs(coalition_iads.SamAsEwr) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - processing IADS SAM as EWR %s", unit.dcsGroupName)) - local iads_unit = iads:addSAMSite(unit.dcsGroupName) - if iads_unit ~= nil then - -- only process if its a valid skynet group - iads_unit:setActAsEW(true) - initializeIADSElement(iads, iads_unit, unit) - end - end - end - if coalition_iads.CommandCenter then - for _, unit in pairs(coalition_iads.CommandCenter) do - env.info(string.format("DCSLiberation|Skynet-IADS plugin - processing IADS Command Center %s", unit.dcsGroupName)) - local commandCenter = StaticObject.getByName(unit.dcsGroupName .. " object") -- pydcs adds ' object' to the unit name for static elements - if commandCenter then - local iads_unit = iads:addCommandCenter(commandCenter) - initializeIADSElement(iads, iads_unit, unit) - end - end - end - end - - if inRadio then - --activate the radio menu to toggle IADS Status output - env.info("DCSLiberation|Skynet-IADS plugin - adding in radio menu") - iads:addRadioMenu() - end - - --activate the IADS - iads:activate() - end - - ------------------------------------------------------------------------------------------------------------------------------------------------------------ - -- create the IADS networks - ------------------------------------------------------------------------------------------------------------------------------------------------------------- - if createRedIADS then - env.info("DCSLiberation|Skynet-IADS plugin - creating red IADS") - local redIADS = SkynetIADS:create("IADS") - initializeIADS(redIADS, 1, includeRedInRadio, debugRED) -- RED - end - - if createBlueIADS then - env.info("DCSLiberation|Skynet-IADS plugin - creating blue IADS") - local blueIADS = SkynetIADS:create("IADS") - initializeIADS(blueIADS, 2, includeBlueInRadio, debugBLUE) -- BLUE - end - -end diff --git a/resources/plugins/splashdamage/LICENSE.md b/resources/plugins/splashdamage/LICENSE.md deleted file mode 100644 index 261eeb9e9..000000000 --- a/resources/plugins/splashdamage/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/resources/plugins/splashdamage/Weapons_Damage_Updated.lua b/resources/plugins/splashdamage/Weapons_Damage_Updated.lua deleted file mode 100644 index 696282d25..000000000 --- a/resources/plugins/splashdamage/Weapons_Damage_Updated.lua +++ /dev/null @@ -1,209 +0,0 @@ - - ---[[ -2 October 2020 -FrozenDroid: -- Added error handling to all event handler and scheduled functions. Lua script errors can no longer bring the server down. -- Added some extra checks to which weapons to handle, make sure they actually have a warhead (how come S-8KOM's don't have a warhead field...?) -28 October 2020 -FrozenDroid: -- Uncommented error logging, actually made it an error log which shows a message box on error. -- Fixed the too restrictive weapon filter (took out the HE warhead requirement) ---]] - -explTable = { - ["FAB_100"] = 45, - ["FAB_250"] = 100, - ["FAB_250M54TU"]= 100, - ["FAB_500"] = 213, - ["FAB_1500"] = 675, - ["BetAB_500"] = 98, - ["BetAB_500ShP"]= 107, - ["KH-66_Grom"] = 108, - ["M_117"] = 201, - ["Mk_81"] = 60, - ["Mk_82"] = 118, - ["AN_M64"] = 121, - ["Mk_83"] = 274, - ["Mk_84"] = 582, - ["MK_82AIR"] = 118, - ["MK_82SNAKEYE"]= 118, - ["GBU_10"] = 582, - ["GBU_12"] = 118, - ["GBU_16"] = 274, - ["KAB_1500Kr"] = 675, - ["KAB_500Kr"] = 213, - ["KAB_500"] = 213, - ["GBU_31"] = 582, - ["GBU_31_V_3B"] = 582, - ["GBU_31_V_2B"] = 582, - ["GBU_31_V_4B"] = 582, - ["GBU_32_V_2B"] = 202, - ["GBU_38"] = 118, - ["AGM_62"] = 400, - ["GBU_24"] = 582, - ["X_23"] = 111, - ["X_23L"] = 111, - ["X_28"] = 160, - ["X_25ML"] = 89, - ["X_25MP"] = 89, - ["X_25MR"] = 140, - ["X_58"] = 140, - ["X_29L"] = 320, - ["X_29T"] = 320, - ["X_29TE"] = 320, - ["AGM_84E"] = 488, - ["AGM_88C"] = 89, - ["AGM_122"] = 15, - ["AGM_123"] = 274, - ["AGM_130"] = 582, - ["AGM_119"] = 176, - ["AGM_154C"] = 305, - ["S-24A"] = 24, - --["S-24B"] = 123, - ["S-25OF"] = 194, - ["S-25OFM"] = 150, - ["S-25O"] = 150, - ["S_25L"] = 190, - ["S-5M"] = 1, - ["C_8"] = 4, - ["C_8OFP2"] = 3, - ["C_13"] = 21, - ["C_24"] = 123, - ["C_25"] = 151, - ["HYDRA_70M15"] = 2, - ["Zuni_127"] = 5, - ["ARAKM70BHE"] = 4, - ["BR_500"] = 118, - ["Rb 05A"] = 217, - ["HEBOMB"] = 40, - ["HEBOMBD"] = 40, - ["MK-81SE"] = 60, - ["AN-M57"] = 56, - ["AN-M64"] = 180, - ["AN-M65"] = 295, - ["AN-M66A2"] = 536, -} - -local weaponDamageEnable = 1 -WpnHandler = {} -tracked_weapons = {} -refreshRate = 0.1 - -local function getDistance(point1, point2) - local x1 = point1.x - local y1 = point1.y - local z1 = point1.z - local x2 = point2.x - local y2 = point2.y - local z2 = point2.z - local dX = math.abs(x1-x2) - local dZ = math.abs(z1-z2) - local distance = math.sqrt(dX*dX + dZ*dZ) - return distance -end - -local function getDistance3D(point1, point2) - local x1 = point1.x - local y1 = point1.y - local z1 = point1.z - local x2 = point2.x - local y2 = point2.y - local z2 = point2.z - local dX = math.abs(x1-x2) - local dY = math.abs(y1-y2) - local dZ = math.abs(z1-z2) - local distance = math.sqrt(dX*dX + dZ*dZ + dY*dY) - return distance -end - -local function vec3Mag(speedVec) - - mag = speedVec.x*speedVec.x + speedVec.y*speedVec.y+speedVec.z*speedVec.z - mag = math.sqrt(mag) - --trigger.action.outText("X = " .. speedVec.x ..", y = " .. speedVec.y .. ", z = "..speedVec.z, 10) - --trigger.action.outText("Speed = " .. mag, 1) - return mag - -end - -local function lookahead(speedVec) - - speed = vec3Mag(speedVec) - dist = speed * refreshRate * 1.5 - return dist - -end - -local function track_wpns() --- env.info("Weapon Track Start") - for wpn_id_, wpnData in pairs(tracked_weapons) do - if wpnData.wpn:isExist() then -- just update speed, position and direction. - wpnData.pos = wpnData.wpn:getPosition().p - wpnData.dir = wpnData.wpn:getPosition().x - wpnData.speed = wpnData.wpn:getVelocity() - --wpnData.lastIP = land.getIP(wpnData.pos, wpnData.dir, 50) - else -- wpn no longer exists, must be dead. --- trigger.action.outText("Weapon impacted, mass of weapon warhead is " .. wpnData.exMass, 2) - local ip = land.getIP(wpnData.pos, wpnData.dir, lookahead(wpnData.speed)) -- terrain intersection point with weapon's nose. Only search out 20 meters though. - local impactPoint - if not ip then -- use last calculated IP - impactPoint = wpnData.pos - -- trigger.action.outText("Impact Point:\nPos X: " .. impactPoint.x .. "\nPos Z: " .. impactPoint.z, 2) - else -- use intersection point - impactPoint = ip - -- trigger.action.outText("Impact Point:\nPos X: " .. impactPoint.x .. "\nPos Z: " .. impactPoint.z, 2) - end - --env.info("Weapon is gone") -- Got to here -- - --trigger.action.outText("Weapon Type was: ".. wpnData.name, 20) - if explTable[wpnData.name] then - --env.info("triggered explosion size: "..explTable[wpnData.name]) - trigger.action.explosion(impactPoint, explTable[wpnData.name]) - --trigger.action.smoke(impactPoint, 0) - end - tracked_weapons[wpn_id_] = nil -- remove from tracked weapons first. - end - end --- env.info("Weapon Track End") -end - -function onWpnEvent(event) - if event.id == world.event.S_EVENT_SHOT then - if event.weapon then - local ordnance = event.weapon - local weapon_desc = ordnance:getDesc() - if (weapon_desc.category ~= 0) and event.initiator then - if (weapon_desc.category == 1) then - if (weapon_desc.MissileCategory ~= 1 and weapon_desc.MissileCategory ~= 2) then - tracked_weapons[event.weapon.id_] = { wpn = ordnance, init = event.initiator:getName(), pos = ordnance:getPoint(), dir = ordnance:getPosition().x, name = ordnance:getTypeName(), speed = ordnance:getVelocity() } - end - else - tracked_weapons[event.weapon.id_] = { wpn = ordnance, init = event.initiator:getName(), pos = ordnance:getPoint(), dir = ordnance:getPosition().x, name = ordnance:getTypeName(), speed = ordnance:getVelocity() } - end - end - end - end -end - -local function protectedCall(...) - local status, retval = pcall(...) - if not status then - env.warning("Splash damage script error... gracefully caught! " .. retval, true) - end -end - - -function WpnHandler:onEvent(event) - protectedCall(onWpnEvent, event) -end - -if (weaponDamageEnable == 1) then - timer.scheduleFunction(function() - protectedCall(track_wpns) - return timer.getTime() + refreshRate - end, - {}, - timer.getTime() + refreshRate - ) - world.addEventHandler(WpnHandler) -end diff --git a/resources/plugins/splashdamage/plugin.json b/resources/plugins/splashdamage/plugin.json deleted file mode 100644 index 5a249a049..000000000 --- a/resources/plugins/splashdamage/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "nameInUI": "Splash Damage", - "defaultValue": false, - "specificOptions": [], - "scriptsWorkOrders": [ - { - "file": "Weapons_Damage_Updated.lua", - "mnemonic": "Splash Damage" - } - ], - "configurationWorkOrders": [] -} diff --git a/resources/scripts/MissionScripting.lua b/resources/scripts/MissionScripting.lua deleted file mode 100644 index fa5709719..000000000 --- a/resources/scripts/MissionScripting.lua +++ /dev/null @@ -1,21 +0,0 @@ ---Initialization script for the Mission lua Environment (SSE) - -dofile('Scripts/ScriptingSystem.lua') - ---Sanitize Mission Scripting environment ---This makes unavailable some unsecure functions. ---Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions. ---You can remove the code below and make availble these functions at your own risk. - --- local function sanitizeModule(name) --- _G[name] = nil --- package.loaded[name] = nil --- end --- --- do --- sanitizeModule('os') --- sanitizeModule('io') --- sanitizeModule('lfs') --- require = nil --- loadlib = nil --- end \ No newline at end of file diff --git a/resources/scripts/MissionScripting.original.lua b/resources/scripts/MissionScripting.original.lua deleted file mode 100644 index 251d11a8a..000000000 --- a/resources/scripts/MissionScripting.original.lua +++ /dev/null @@ -1,22 +0,0 @@ ---Initialization script for the Mission lua Environment (SSE) - -dofile('Scripts/ScriptingSystem.lua') - ---Sanitize Mission Scripting environment ---This makes unavailable some unsecure functions. ---Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions. ---You can remove the code below and make availble these functions at your own risk. - -local function sanitizeModule(name) - _G[name] = nil - package.loaded[name] = nil -end - -do - sanitizeModule('os') - sanitizeModule('io') - sanitizeModule('lfs') - _G['require'] = nil - _G['loadlib'] = nil - _G['package'] = nil -end diff --git a/resources/squadrons/A-10A Warthog/104th FS.yaml b/resources/squadrons/A-10A Warthog/104th FS.yaml deleted file mode 100644 index 459cc1b12..000000000 --- a/resources/squadrons/A-10A Warthog/104th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 104th FS -nickname: Eagles -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 104th FS Maryland ANG, Baltimore (MD) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/118th FS.yaml b/resources/squadrons/A-10A Warthog/118th FS.yaml deleted file mode 100644 index f8fc0a1c6..000000000 --- a/resources/squadrons/A-10A Warthog/118th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 118th FS -nickname: Flying Yankees -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 118th FS Bradley ANGB, Connecticut (CT) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/172nd FS.yaml b/resources/squadrons/A-10A Warthog/172nd FS.yaml deleted file mode 100644 index 5ea82deba..000000000 --- a/resources/squadrons/A-10A Warthog/172nd FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 172nd FS -nickname: -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 172nd FS Battle Creek ANGB, Michigan (BC) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/184th FS.yaml b/resources/squadrons/A-10A Warthog/184th FS.yaml deleted file mode 100644 index 97d6e81cd..000000000 --- a/resources/squadrons/A-10A Warthog/184th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 184th FS -nickname: Flying Razorbacks -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 184th FS Arkansas ANG, Fort Smith (FS) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/190th FS.yaml b/resources/squadrons/A-10A Warthog/190th FS.yaml deleted file mode 100644 index 3b93265b3..000000000 --- a/resources/squadrons/A-10A Warthog/190th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 190th FS -nickname: Skull Bangers -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 190th FS Boise ANGB, Idaho (ID) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/25th FS.yaml b/resources/squadrons/A-10A Warthog/25th FS.yaml deleted file mode 100644 index 48ca5f202..000000000 --- a/resources/squadrons/A-10A Warthog/25th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 25th FS -nickname: Assam Draggins -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 25th FS Osab AB, Korea (OS) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/354th FS.yaml b/resources/squadrons/A-10A Warthog/354th FS.yaml deleted file mode 100644 index 615040477..000000000 --- a/resources/squadrons/A-10A Warthog/354th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 354th FS -nickname: Bulldogs -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 354th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/355th FS.yaml b/resources/squadrons/A-10A Warthog/355th FS.yaml deleted file mode 100644 index 5bc7bbdcd..000000000 --- a/resources/squadrons/A-10A Warthog/355th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 355th FS -nickname: Fightin' Falcons -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 355th FS Eielson AFB, Alaska (AK) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/357th FS.yaml b/resources/squadrons/A-10A Warthog/357th FS.yaml deleted file mode 100644 index 705d82d82..000000000 --- a/resources/squadrons/A-10A Warthog/357th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 357th FS -nickname: Dragons -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 357th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/358th FS.yaml b/resources/squadrons/A-10A Warthog/358th FS.yaml deleted file mode 100644 index 769a9207f..000000000 --- a/resources/squadrons/A-10A Warthog/358th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 358th FS -nickname: Lobos -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 358th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/47th FS.yaml b/resources/squadrons/A-10A Warthog/47th FS.yaml deleted file mode 100644 index ddac7090d..000000000 --- a/resources/squadrons/A-10A Warthog/47th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 47th FS -nickname: Termites -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 47th FS Barksdale AFB, Louisiana (BD) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/74th TFS.yaml b/resources/squadrons/A-10A Warthog/74th TFS.yaml deleted file mode 100644 index b0a5c7ef7..000000000 --- a/resources/squadrons/A-10A Warthog/74th TFS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 74th TFS -nickname: Flying Tigers -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 23rd TFW England AFB (EL) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10A Warthog/81st FS.yaml b/resources/squadrons/A-10A Warthog/81st FS.yaml deleted file mode 100644 index 5275187fe..000000000 --- a/resources/squadrons/A-10A Warthog/81st FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 81st FS -nickname: Termites -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10A Thunderbolt II -livery: 81st FS Spangdahlem AB, Germany (SP) 2 -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/104th FS.yaml b/resources/squadrons/A-10C Warthog I/104th FS.yaml deleted file mode 100644 index f76fb4006..000000000 --- a/resources/squadrons/A-10C Warthog I/104th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 104th FS -nickname: Eagles -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 104th FS Maryland ANG, Baltimore (MD) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/118th FS.yaml b/resources/squadrons/A-10C Warthog I/118th FS.yaml deleted file mode 100644 index f66364640..000000000 --- a/resources/squadrons/A-10C Warthog I/118th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 118th FS -nickname: Flying Yankees -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 118th FS Bradley ANGB, Connecticut (CT) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/172nd FS.yaml b/resources/squadrons/A-10C Warthog I/172nd FS.yaml deleted file mode 100644 index 052bcda5c..000000000 --- a/resources/squadrons/A-10C Warthog I/172nd FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 172nd FS -nickname: -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 172nd FS Battle Creek ANGB, Michigan (BC) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/184th FS.yaml b/resources/squadrons/A-10C Warthog I/184th FS.yaml deleted file mode 100644 index 946d99874..000000000 --- a/resources/squadrons/A-10C Warthog I/184th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 184th FS -nickname: Flying Razorbacks -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 184th FS Arkansas ANG, Fort Smith (FS) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/190th FS.yaml b/resources/squadrons/A-10C Warthog I/190th FS.yaml deleted file mode 100644 index f0b3da721..000000000 --- a/resources/squadrons/A-10C Warthog I/190th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 190th FS -nickname: Skull Bangers -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 190th FS Boise ANGB, Idaho (ID) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/25th FS.yaml b/resources/squadrons/A-10C Warthog I/25th FS.yaml deleted file mode 100644 index f7b324594..000000000 --- a/resources/squadrons/A-10C Warthog I/25th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 25th FS -nickname: Assam Draggins -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 25th FS Osab AB, Korea (OS) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/354th FS.yaml b/resources/squadrons/A-10C Warthog I/354th FS.yaml deleted file mode 100644 index 8ecc28f78..000000000 --- a/resources/squadrons/A-10C Warthog I/354th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 354th FS -nickname: Bulldogs -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 354th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/355th FS.yaml b/resources/squadrons/A-10C Warthog I/355th FS.yaml deleted file mode 100644 index fea5ff9bb..000000000 --- a/resources/squadrons/A-10C Warthog I/355th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 355th FS -nickname: Fightin' Falcons -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 355th FS Eielson AFB, Alaska (AK) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/357th FS.yaml b/resources/squadrons/A-10C Warthog I/357th FS.yaml deleted file mode 100644 index eaabd3a93..000000000 --- a/resources/squadrons/A-10C Warthog I/357th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 357th FS -nickname: Dragons -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 357th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/358th FS.yaml b/resources/squadrons/A-10C Warthog I/358th FS.yaml deleted file mode 100644 index 2240e73ec..000000000 --- a/resources/squadrons/A-10C Warthog I/358th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 358th FS -nickname: Lobos -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 358th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/47th FS.yaml b/resources/squadrons/A-10C Warthog I/47th FS.yaml deleted file mode 100644 index 93db63e06..000000000 --- a/resources/squadrons/A-10C Warthog I/47th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 47th FS -nickname: Termites -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 47th FS Barksdale AFB, Louisiana (BD) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/74th TFS.yaml b/resources/squadrons/A-10C Warthog I/74th TFS.yaml deleted file mode 100644 index dcbfe4c8d..000000000 --- a/resources/squadrons/A-10C Warthog I/74th TFS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 74th TFS -nickname: Flying Tigers -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 23rd TFW England AFB (EL) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog I/81st FS.yaml b/resources/squadrons/A-10C Warthog I/81st FS.yaml deleted file mode 100644 index 0324751d7..000000000 --- a/resources/squadrons/A-10C Warthog I/81st FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 81st FS -nickname: Termites -female_pilot_percentage: 0 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 3) -livery: 81st FS Spangdahlem AB, Germany (SP) 2 -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/25th FS.yaml b/resources/squadrons/A-10C Warthog II/25th FS.yaml deleted file mode 100644 index 5cee12a6c..000000000 --- a/resources/squadrons/A-10C Warthog II/25th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 25th FS -nickname: Assam Draggins -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 25th FS Osab AB, Korea (OS) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/354th FS.yaml b/resources/squadrons/A-10C Warthog II/354th FS.yaml deleted file mode 100644 index 5f0399611..000000000 --- a/resources/squadrons/A-10C Warthog II/354th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 354th FS -nickname: Bulldogs -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 354th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/355th FS.yaml b/resources/squadrons/A-10C Warthog II/355th FS.yaml deleted file mode 100644 index c7574a02d..000000000 --- a/resources/squadrons/A-10C Warthog II/355th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 355th FS -nickname: Fightin' Falcons -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 355th FS Eielson AFB, Alaska (AK) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/357th FS.yaml b/resources/squadrons/A-10C Warthog II/357th FS.yaml deleted file mode 100644 index e4210f52b..000000000 --- a/resources/squadrons/A-10C Warthog II/357th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 357th FS -nickname: Dragons -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 357th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/358th FS.yaml b/resources/squadrons/A-10C Warthog II/358th FS.yaml deleted file mode 100644 index 7f2bff230..000000000 --- a/resources/squadrons/A-10C Warthog II/358th FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 358th FS -nickname: Lobos -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 358th FS Davis Monthan AFB, Arizona (DM) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-10C Warthog II/81st FS.yaml b/resources/squadrons/A-10C Warthog II/81st FS.yaml deleted file mode 100644 index 91af7ae42..000000000 --- a/resources/squadrons/A-10C Warthog II/81st FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 81st FS -nickname: Termites -female_pilot_percentage: 6 -country: USA -role: Close Air Support -aircraft: A-10C Thunderbolt II (Suite 7) -livery: 81st FS Spangdahlem AB, Germany (SP) 2 -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/A-4E Skyhawk/IAF 110th Sqn.yaml b/resources/squadrons/A-4E Skyhawk/IAF 110th Sqn.yaml deleted file mode 100644 index 228f96189..000000000 --- a/resources/squadrons/A-4E Skyhawk/IAF 110th Sqn.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: 110th Squadron -nickname: Knights of the North -female_pilot_percentage: 0 -country: Israel -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: false - shore: true -livery: International Israel -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/iaf-north-squadron diff --git a/resources/squadrons/A-4E Skyhawk/VA-144.yaml b/resources/squadrons/A-4E Skyhawk/VA-144.yaml deleted file mode 100644 index facb5d35b..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-144.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-144 -nickname: Roadrunners -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-144 Roadrunners -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va144 diff --git a/resources/squadrons/A-4E Skyhawk/VA-153.yaml b/resources/squadrons/A-4E Skyhawk/VA-153.yaml deleted file mode 100644 index 247c625dc..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-153.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-153 -nickname: Blue Tail Flies -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-153 Blue Tail Flies -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va153 diff --git a/resources/squadrons/A-4E Skyhawk/VA-163.yaml b/resources/squadrons/A-4E Skyhawk/VA-163.yaml deleted file mode 100644 index aedf7f98d..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-163.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-163 -nickname: Saints -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-163 Saints -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va163 diff --git a/resources/squadrons/A-4E Skyhawk/VA-164.yaml b/resources/squadrons/A-4E Skyhawk/VA-164.yaml deleted file mode 100644 index c6b0094f6..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-164.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-164 -nickname: Ghostriders -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-164 Ghostriders -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va164 diff --git a/resources/squadrons/A-4E Skyhawk/VA-195.yaml b/resources/squadrons/A-4E Skyhawk/VA-195.yaml deleted file mode 100644 index 028d7494b..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-195.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-195 -nickname: Dambusters -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-195 Dambusters -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va195 diff --git a/resources/squadrons/A-4E Skyhawk/VA-212.yaml b/resources/squadrons/A-4E Skyhawk/VA-212.yaml deleted file mode 100644 index 3a504511f..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-212.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-212 -nickname: Rampant Raiders -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-212 Rampant Raiders -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va212 diff --git a/resources/squadrons/A-4E Skyhawk/VA-45.yaml b/resources/squadrons/A-4E Skyhawk/VA-45.yaml deleted file mode 100644 index 88ae45ecb..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-45.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-45 -nickname: Blackbirds -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-45 Blackbirds -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va45 diff --git a/resources/squadrons/A-4E Skyhawk/VA-55.yaml b/resources/squadrons/A-4E Skyhawk/VA-55.yaml deleted file mode 100644 index d974233c0..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-55.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-55 -nickname: Warhorses -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-55 Warhorses -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va55 diff --git a/resources/squadrons/A-4E Skyhawk/VA-64.yaml b/resources/squadrons/A-4E Skyhawk/VA-64.yaml deleted file mode 100644 index 0ba2c5caf..000000000 --- a/resources/squadrons/A-4E Skyhawk/VA-64.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VA-64 -nickname: Black Lancers -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -livery: USN VA-64 Black Lancers -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/va64 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-121.yaml b/resources/squadrons/A-4E Skyhawk/VMA-121.yaml deleted file mode 100644 index 8a6afcb65..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-121.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-121 -nickname: Green Knights -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-121 Green Knights -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma121 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-124.yaml b/resources/squadrons/A-4E Skyhawk/VMA-124.yaml deleted file mode 100644 index ba8cb5564..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-124.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -name: VMA-124 -nickname: Memphis Marines -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-124 Memphis Marines -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/A-4E Skyhawk/VMA-131.yaml b/resources/squadrons/A-4E Skyhawk/VMA-131.yaml deleted file mode 100644 index a28b90c10..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-131.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-131 -nickname: Diamondbacks -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-131 Diamondbacks -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma131 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-142.yaml b/resources/squadrons/A-4E Skyhawk/VMA-142.yaml deleted file mode 100644 index 793a2c73a..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-142.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-142 -nickname: Flying Gators -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-142 Flying Gators -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma142 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-211.yaml b/resources/squadrons/A-4E Skyhawk/VMA-211.yaml deleted file mode 100644 index 3e3be7d88..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-211.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-211 -nickname: Avengers -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-211 Avengers -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma211 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-311.yaml b/resources/squadrons/A-4E Skyhawk/VMA-311.yaml deleted file mode 100644 index 032b4fbf8..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-311.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-311 -nickname: Tomcats -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-311 Tomcats -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma311 diff --git a/resources/squadrons/A-4E Skyhawk/VMA-322.yaml b/resources/squadrons/A-4E Skyhawk/VMA-322.yaml deleted file mode 100644 index 2eba9d993..000000000 --- a/resources/squadrons/A-4E Skyhawk/VMA-322.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -name: VMA-322 -nickname: Fighting Gamecocks -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack/Light Fighter -aircraft: A-4E Skyhawk -bases: - carrier: true - shore: true -livery: USMC VMA-322 Fighting Gamecocks -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP -# http://skyhawk.org/article-unit/vma322 diff --git a/resources/squadrons/A20/no_107_squadron_raf.yaml b/resources/squadrons/A20/no_107_squadron_raf.yaml deleted file mode 100644 index 1a72d892b..000000000 --- a/resources/squadrons/A20/no_107_squadron_raf.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: RAF, No. 107 Squadron -nickname: Lowestoft's 'own' Squadron -female_pilot_percentage: 0 -country: UK -role: Medium Bomber -aircraft: Boston Mk.III -livery: 107 Sqn -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/AH-1X/HMLA-169-AH1W.yaml b/resources/squadrons/AH-1X/HMLA-169-AH1W.yaml deleted file mode 100644 index d435c737b..000000000 --- a/resources/squadrons/AH-1X/HMLA-169-AH1W.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: HMLA-169 (AH-1W) -nickname: Vipers -female_pilot_percentage: 0 -country: USA -role: Attack -aircraft: AH-1W SuperCobra -livery: USA Marines -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft diff --git a/resources/squadrons/AH-1X/HMLA-269-AH1W.yaml b/resources/squadrons/AH-1X/HMLA-269-AH1W.yaml deleted file mode 100644 index b64b3f1d9..000000000 --- a/resources/squadrons/AH-1X/HMLA-269-AH1W.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: HMLA-269 (AH-1W) -nickname: Gunrunners -female_pilot_percentage: 0 -country: USA -role: Attack -aircraft: AH-1W SuperCobra -livery: USA Marines -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft diff --git a/resources/squadrons/AH-1X/IAF 160th Sqn.yaml b/resources/squadrons/AH-1X/IAF 160th Sqn.yaml deleted file mode 100644 index 72a3f0c97..000000000 --- a/resources/squadrons/AH-1X/IAF 160th Sqn.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: 160th Squadron -nickname: Northern Cobra Squadron -female_pilot_percentage: 0 -country: Israel -role: Attack Helicopter -aircraft: AH-1W SuperCobra -livery: ah-64_d_isr -mission_types: - - CAS - - BAI - diff --git a/resources/squadrons/AH-64D/A Company, 1-211th ARB.yaml b/resources/squadrons/AH-64D/A Company, 1-211th ARB.yaml deleted file mode 100644 index b81908d3c..000000000 --- a/resources/squadrons/AH-64D/A Company, 1-211th ARB.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: A Company, 1-211th ARB -nickname: Air Pirates -female_pilot_percentage: 10 -country: USA -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: The Air Pirates 1-211th ARB -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AH-64D/A Company, 1-227th ARB.yaml b/resources/squadrons/AH-64D/A Company, 1-227th ARB.yaml deleted file mode 100644 index 63b93836a..000000000 --- a/resources/squadrons/AH-64D/A Company, 1-227th ARB.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: A Company, 1-227th ARB -nickname: Avengers -female_pilot_percentage: 10 -country: USA -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: Avengers 1-227th ARB -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AH-64D/C Company, 2-159th ARB.yaml b/resources/squadrons/AH-64D/C Company, 2-159th ARB.yaml deleted file mode 100644 index be647e564..000000000 --- a/resources/squadrons/AH-64D/C Company, 2-159th ARB.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: C Company, 2-159th ARB -nickname: Gunslingers -female_pilot_percentage: 10 -country: USA -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: Gunslingers 2-159th ARB -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AH-64D/IAF 113th Sqn.yaml b/resources/squadrons/AH-64D/IAF 113th Sqn.yaml deleted file mode 100644 index 323e41b5a..000000000 --- a/resources/squadrons/AH-64D/IAF 113th Sqn.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 113th Squadron -nickname: The Hornet Squadron -female_pilot_percentage: 5 -country: Israel -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: standard -mission_types: - - CAS - - BAI diff --git a/resources/squadrons/AH-64D/RNLAF Redskins 301 Sqn.yaml b/resources/squadrons/AH-64D/RNLAF Redskins 301 Sqn.yaml deleted file mode 100644 index 921cc9f3f..000000000 --- a/resources/squadrons/AH-64D/RNLAF Redskins 301 Sqn.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: RNLAF Redskins 301 Sqn -nickname: Redskins -female_pilot_percentage: 2 -country: The Netherlands -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: 301 Squadron Redskins Netherlands -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AH-64D/US Army 229th Aviation Battalion.yaml b/resources/squadrons/AH-64D/US Army 229th Aviation Battalion.yaml deleted file mode 100644 index 1d081b63b..000000000 --- a/resources/squadrons/AH-64D/US Army 229th Aviation Battalion.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: 229th Aviation Battalion -nickname: Serpents -female_pilot_percentage: 6 -country: USA -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: standard -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AH-64D/Wolfpack, 1-82 ARB.yaml b/resources/squadrons/AH-64D/Wolfpack, 1-82 ARB.yaml deleted file mode 100644 index 24605c6d1..000000000 --- a/resources/squadrons/AH-64D/Wolfpack, 1-82 ARB.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: Wolfpack, 1-82 ARB -nickname: Wolfpack -female_pilot_percentage: 10 -country: USA -role: Attack Helicopter -aircraft: AH-64D Apache Longbow -livery: Wolfpack 1-82 ARB -mission_types: - - CAS - - BAI - - OCA/Aircraft diff --git a/resources/squadrons/AV-8BNA/VMA-214.yaml b/resources/squadrons/AV-8BNA/VMA-214.yaml deleted file mode 100644 index 1d5d44e36..000000000 --- a/resources/squadrons/AV-8BNA/VMA-214.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VMA-214 -nickname: Black Sheep -female_pilot_percentage: 0 -country: USA -role: V/STOL Attack -aircraft: AV-8B Harrier II Night Attack -bases: - carrier: false - shore: true - lha: true -livery: VMA-214D -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike diff --git a/resources/squadrons/AV-8BNA/VMA-223.yaml b/resources/squadrons/AV-8BNA/VMA-223.yaml deleted file mode 100644 index c044416c8..000000000 --- a/resources/squadrons/AV-8BNA/VMA-223.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: VMA-223 -nickname: Bulldogs -female_pilot_percentage: 0 -country: USA -role: V/STOL Attack -aircraft: AV-8B Harrier II Night Attack -bases: - carrier: false - shore: true - lha: true -livery: VMA-223D -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike diff --git a/resources/squadrons/BF-109K4/Jagdgeschwader_53.yaml b/resources/squadrons/BF-109K4/Jagdgeschwader_53.yaml deleted file mode 100644 index 858eaf992..000000000 --- a/resources/squadrons/BF-109K4/Jagdgeschwader_53.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: Jagdgeschwader 53 -nickname: Pik As -female_pilot_percentage: 0 -country: Third Reich -role: Fighter -aircraft: Bf 109 K-4 Kurfürst -livery: Bf-109 K4 Jagdgeschwader 53 -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/E-2 Hawkeye/VAW-125.yaml b/resources/squadrons/E-2 Hawkeye/VAW-125.yaml deleted file mode 100644 index 3e694b419..000000000 --- a/resources/squadrons/E-2 Hawkeye/VAW-125.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: VAW-125 -nickname: Tigertails -female_pilot_percentage: 6 -country: USA -role: AEW&C -aircraft: E-2C Hawkeye -livery: VAW-125 Tigertails -mission_types: - - AEW&C diff --git a/resources/squadrons/E-3 Sentry/USAF 960th AACS.yaml b/resources/squadrons/E-3 Sentry/USAF 960th AACS.yaml deleted file mode 100644 index ea97f6131..000000000 --- a/resources/squadrons/E-3 Sentry/USAF 960th AACS.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: 960th AAC Squadron -nickname: Vikings -female_pilot_percentage: 6 -country: USA -role: AEW&C -aircraft: E-3A -livery: usaf standard -mission_types: - - AEW&C diff --git a/resources/squadrons/Eagle/IAF 106th Sqn.yaml b/resources/squadrons/Eagle/IAF 106th Sqn.yaml deleted file mode 100644 index 7b598be15..000000000 --- a/resources/squadrons/Eagle/IAF 106th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 106th Squadron -nickname: Spearhead -female_pilot_percentage: 6 -country: Israel -role: Air Superiority Fighter -aircraft: F-15C Eagle -livery: 106th SQN (8th Airbase) -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - diff --git a/resources/squadrons/Eagle/USAF 12th FS.yaml b/resources/squadrons/Eagle/USAF 12th FS.yaml deleted file mode 100644 index 36daa2330..000000000 --- a/resources/squadrons/Eagle/USAF 12th FS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 12th FS -nickname: Dirty Dozen -female_pilot_percentage: 6 -country: USA -role: Air Superiority Fighter -aircraft: F-15C Eagle -livery: 12th Fighter SQN (AK) -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - diff --git a/resources/squadrons/Eagle/USAF 390th FS.yaml b/resources/squadrons/Eagle/USAF 390th FS.yaml deleted file mode 100644 index 8f93a0c26..000000000 --- a/resources/squadrons/Eagle/USAF 390th FS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 390th FS -nickname: Wild Boars -female_pilot_percentage: 6 -country: USA -role: Air Superiority Fighter -aircraft: F-15C Eagle -livery: 390th Fighter SQN -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - diff --git a/resources/squadrons/Eagle/USAF 493rd FS.yaml b/resources/squadrons/Eagle/USAF 493rd FS.yaml deleted file mode 100644 index cb2ec5fc7..000000000 --- a/resources/squadrons/Eagle/USAF 493rd FS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 493rd FS -nickname: Grim Reapers -female_pilot_percentage: 6 -country: USA -role: Air Superiority Fighter -aircraft: F-15C Eagle -livery: 493rd Fighter SQN (LN) -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - diff --git a/resources/squadrons/Eagle/USAF 58th FS.yaml b/resources/squadrons/Eagle/USAF 58th FS.yaml deleted file mode 100644 index 3f95bfb81..000000000 --- a/resources/squadrons/Eagle/USAF 58th FS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 58th FS -nickname: Gorillas -female_pilot_percentage: 6 -country: USA -role: Air Superiority Fighter -aircraft: F-15C Eagle -livery: 58th Fighter SQN (EG) -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - diff --git a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-11.yaml b/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-11.yaml deleted file mode 100644 index 4b5dfc990..000000000 --- a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-11.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-11 -nickname: Red Rippers -female_pilot_percentage: 0 -country: USA -role: Strike Fighter -aircraft: F-14A Tomcat (Block 135-GR Late) -livery: VF-11 Red Rippers 106 -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-111.yaml b/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-111.yaml deleted file mode 100644 index dd3713b0f..000000000 --- a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-111.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-111 -nickname: Sundowners -female_pilot_percentage: 0 -country: USA -role: Strike Fighter -aircraft: F-14A Tomcat (Block 135-GR Late) -livery: VF-111 Sundowners 200 -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-21.yaml b/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-21.yaml deleted file mode 100644 index fd6416f5c..000000000 --- a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-21.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-21 -nickname: Freelancers -female_pilot_percentage: 0 -country: USA -role: Strike Fighter -aircraft: F-14A Tomcat (Block 135-GR Late) -livery: VF-21 Freelancers 200 -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-211.yaml b/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-211.yaml deleted file mode 100644 index 3d02f4c8e..000000000 --- a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-211.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-211 -nickname: Fighting Checkmates -female_pilot_percentage: 0 -country: USA -role: Strike Fighter -aircraft: F-14A Tomcat (Block 135-GR Late) -livery: VF-211 Fighting Checkmates 105 -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-33.yaml b/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-33.yaml deleted file mode 100644 index 1fdfb9a41..000000000 --- a/resources/squadrons/F-14A 135-GR Tomcat (Late)/VF-33.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-33 -nickname: Starfighters -female_pilot_percentage: 0 -country: USA -role: Strike Fighter -aircraft: F-14A Tomcat (Block 135-GR Late) -livery: VF-33 Starfighters AB201(Dale Snodgrass) -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14B Tomcat/VF-101.yaml b/resources/squadrons/F-14B Tomcat/VF-101.yaml deleted file mode 100644 index ea5ee1fc6..000000000 --- a/resources/squadrons/F-14B Tomcat/VF-101.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-101 -nickname: Grim Reapers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-14B Tomcat -livery: VF-101 Dark -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14B Tomcat/VF-102.yaml b/resources/squadrons/F-14B Tomcat/VF-102.yaml deleted file mode 100644 index 5ee59260c..000000000 --- a/resources/squadrons/F-14B Tomcat/VF-102.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-102 -nickname: Diamond Backs -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-14B Tomcat -livery: VF-102 Diamondbacks 102 (2000) -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14B Tomcat/VF-142.yaml b/resources/squadrons/F-14B Tomcat/VF-142.yaml deleted file mode 100644 index 2d4879431..000000000 --- a/resources/squadrons/F-14B Tomcat/VF-142.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-142 -nickname: Ghostriders -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-14B Tomcat -livery: VF-142 Ghostriders -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14B Tomcat/VF-143.yaml b/resources/squadrons/F-14B Tomcat/VF-143.yaml deleted file mode 100644 index 5e9a82699..000000000 --- a/resources/squadrons/F-14B Tomcat/VF-143.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-143 -nickname: Pukin' Dogs -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-14B Tomcat -livery: VF-143 Pukin Dogs CAG -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-14B Tomcat/VF-211.yaml b/resources/squadrons/F-14B Tomcat/VF-211.yaml deleted file mode 100644 index dcb939954..000000000 --- a/resources/squadrons/F-14B Tomcat/VF-211.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: VF-211 -nickname: Fighting Checkmates -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-14B Tomcat -livery: VF-211 Fighting Checkmates -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/17-WS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/17-WS.yaml deleted file mode 100644 index c6889ed2a..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/17-WS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 17th Weapons Squadron -nickname: Hooters -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 17th WS AF90 Low Vis Clean diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/333-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/333-FS.yaml deleted file mode 100644 index 63bda8255..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/333-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 333rd Fighter Squadron -nickname: Lancers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 333rd Rocketeers FS AF87-199 333 FGS diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/334-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/334-FS.yaml deleted file mode 100644 index 31d1c9812..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/334-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 334th Fighter Squadron -nickname: Eagles -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 334th Eagles FS AF89 Aim High diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/335-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/335-FS.yaml deleted file mode 100644 index 3f34e3c71..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/335-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 335th Fighter Squadron -nickname: Chiefs -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 335th Chiefs FS AF89 Low Vis Combat diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/336-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/336-FS.yaml deleted file mode 100644 index 2dd671318..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/336-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 336th Fighter Squadron -nickname: Rocketeers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 336th Rocketeers FS AF88 Low Vis Combat diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/389-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/389-FS.yaml deleted file mode 100644 index fa2d965b0..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/389-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 389th Fighter Squadron -nickname: Thunderbolts -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 389th Thunderbolts FS AF90 Low Vis Combat diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/391-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/391-FS.yaml deleted file mode 100644 index 935eca7f3..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/391-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 391st Fighter Squadron -nickname: Bold Tigers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 391st Bold Tigers FS AF90-241 High Vis Combat diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/492-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/492-FS.yaml deleted file mode 100644 index 23deed0f2..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/492-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 492th Fighter Squadron -nickname: Madhatters -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 492nd Madhatters FS AF91-315 Vader diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/494-FS.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/494-FS.yaml deleted file mode 100644 index fd131df41..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/494-FS.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 494th Fighter Squadron -nickname: Panthers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: USAF 494th Panthers FS 91-603 75th D-Day Anniversary diff --git a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/69-SQ.yaml b/resources/squadrons/F-15E Strike Eagle (Suite 4+)/69-SQ.yaml deleted file mode 100644 index b8d1be727..000000000 --- a/resources/squadrons/F-15E Strike Eagle (Suite 4+)/69-SQ.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: 69th Squadron -nickname: Hammers -female_pilot_percentage: 7 -country: Israel -role: Strike Fighter -aircraft: F-15E Strike Eagle (Suite 4+) -livery: IDF RA'AM, 69 Hammer Sqn diff --git a/resources/squadrons/F-4B/VF-151.yaml b/resources/squadrons/F-4B/VF-151.yaml deleted file mode 100644 index 38a4e1519..000000000 --- a/resources/squadrons/F-4B/VF-151.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: VF-151 -nickname: Vigilantes -female_pilot_percentage: 0 -country: USA -role: Fighter-Bomber -aircraft: F-4B Phantom II -livery: "VF-151 213 USS MIDWAY" -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4B/VF-51.yaml b/resources/squadrons/F-4B/VF-51.yaml deleted file mode 100644 index d2046693e..000000000 --- a/resources/squadrons/F-4B/VF-51.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: VF-51 -nickname: Screaming Eagles -female_pilot_percentage: 0 -country: USA -role: Fighter-Bomber -aircraft: F-4B Phantom II -livery: "VF-51 100 USS CORAL SEA" -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4B/VMFA-212.yaml b/resources/squadrons/F-4B/VMFA-212.yaml deleted file mode 100644 index 458fe3d7c..000000000 --- a/resources/squadrons/F-4B/VMFA-212.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: VMFA-212 -nickname: Lancers -female_pilot_percentage: 0 -country: USA -role: Fighter-Bomber -aircraft: F-4B Phantom II -livery: "VMFA-212 AC01" -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4C/43 TFS.yaml b/resources/squadrons/F-4C/43 TFS.yaml deleted file mode 100644 index fe864e48b..000000000 --- a/resources/squadrons/F-4C/43 TFS.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: 43rd TFS -nickname: Hornets -female_pilot_percentage: 0 -country: USA -role: Fighter-Bomber -aircraft: F-4C Phantom II -livery: "USAF 40646" -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4C/433 TFS.yaml b/resources/squadrons/F-4C/433 TFS.yaml deleted file mode 100644 index d80316e5a..000000000 --- a/resources/squadrons/F-4C/433 TFS.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -name: 433rd TFS -nickname: Satan's Angels -female_pilot_percentage: 0 -country: USA -role: Fighter-Bomber -aircraft: F-4C Phantom II -livery: "433 TFS 63-7680" -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4E/IAF 201th Sqn.yaml b/resources/squadrons/F-4E/IAF 201th Sqn.yaml deleted file mode 100644 index 9491dd7fc..000000000 --- a/resources/squadrons/F-4E/IAF 201th Sqn.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: 201th Squadron -nickname: The One -female_pilot_percentage: 0 -country: Israel -role: Air Superiority Fighter -aircraft: F-4E Phantom II -livery: "af standard" -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4E/IRIAF 31 TFS.yaml b/resources/squadrons/F-4E/IRIAF 31 TFS.yaml deleted file mode 100644 index 1530a4f63..000000000 --- a/resources/squadrons/F-4E/IRIAF 31 TFS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: IRIAF 31 TFS -nickname: 31 TFS -country: Iran -role: Air Superiority Fighter -aircraft: F-4E Phantom II -livery: IRIAF Asia Minor -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4E/IRIAF 32nd TFW.yaml b/resources/squadrons/F-4E/IRIAF 32nd TFW.yaml deleted file mode 100644 index 61b9c034d..000000000 --- a/resources/squadrons/F-4E/IRIAF 32nd TFW.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: IRIAF 32nd TFW -nickname: 32nd TFW -female_pilot_percentage: 0 -country: Iran -role: Air Superiority Fighter -aircraft: F-4E Phantom II -livery: IRIAF Asia Minor -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4E/IRIAF 61 TFS.yaml b/resources/squadrons/F-4E/IRIAF 61 TFS.yaml deleted file mode 100644 index b3d025430..000000000 --- a/resources/squadrons/F-4E/IRIAF 61 TFS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: IRIAF 61 TFS -nickname: 61 TFS -country: Iran -role: Air Superiority Fighter -aircraft: F-4E Phantom II -livery: IRIAF Asia Minor -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/F-4E/IRIAF 91 TFS.yaml b/resources/squadrons/F-4E/IRIAF 91 TFS.yaml deleted file mode 100644 index dfa5a6d5c..000000000 --- a/resources/squadrons/F-4E/IRIAF 91 TFS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: IRIAF 91 TFS -nickname: 91 TFS -country: Iran -role: Air Superiority Fighter -aircraft: F-4E Phantom II -livery: IRIAF Asia Minor -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/FW-190A8/Jagdgeschwader_26.yaml b/resources/squadrons/FW-190A8/Jagdgeschwader_26.yaml deleted file mode 100644 index 907d80dda..000000000 --- a/resources/squadrons/FW-190A8/Jagdgeschwader_26.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: Jagdgeschwader 26 -nickname: Schlageter -female_pilot_percentage: 0 -country: Third Reich -role: Fighter -aircraft: Fw 190 A-8 Anton -livery: FW-190A8 JG26 Priller -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/FW-190D9/Jagdgeschwader_54.yaml b/resources/squadrons/FW-190D9/Jagdgeschwader_54.yaml deleted file mode 100644 index 8d0d8c32e..000000000 --- a/resources/squadrons/FW-190D9/Jagdgeschwader_54.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: Jagdgeschwader 54 -nickname: Grünherz -female_pilot_percentage: 0 -country: Third Reich -role: Fighter -aircraft: Fw 190 D-9 Dora -livery: FW-190D9_JG54 -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/Ju88A4/Kustenfliegergruppe_106.yaml b/resources/squadrons/Ju88A4/Kustenfliegergruppe_106.yaml deleted file mode 100644 index fd9eaaa5c..000000000 --- a/resources/squadrons/Ju88A4/Kustenfliegergruppe_106.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Küstenfliegergruppe 106 -nickname: Kü.Fl.Gr.206. -female_pilot_percentage: 0 -country: Third Reich -role: Medium Bomber -aircraft: Ju 88 A-4 -female_pilot_percentage: 0 -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/KC-130/VMGR-352.yaml b/resources/squadrons/KC-130/VMGR-352.yaml deleted file mode 100644 index 87fe0f5ed..000000000 --- a/resources/squadrons/KC-130/VMGR-352.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: VMGR-352 -nickname: Raiders -female_pilot_percentage: 6 -country: USA -role: Air-to-Air Refueling -aircraft: KC-130 -mission_types: - - Refueling diff --git a/resources/squadrons/KC-135/18th ARS.yaml b/resources/squadrons/KC-135/18th ARS.yaml deleted file mode 100644 index 87a5f6c6a..000000000 --- a/resources/squadrons/KC-135/18th ARS.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: 18th Air Refueling Squadron -nickname: Kanza -female_pilot_percentage: 6 -country: USA -role: Air-to-Air Refueling -aircraft: KC-135 Stratotanker -mission_types: - - Refueling diff --git a/resources/squadrons/KC-135/TuAF 101st Tanker Squadron.yaml b/resources/squadrons/KC-135/TuAF 101st Tanker Squadron.yaml deleted file mode 100644 index 4ff0bd10f..000000000 --- a/resources/squadrons/KC-135/TuAF 101st Tanker Squadron.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: 101st Tanker Squadron -nickname: Asena -female_pilot_percentage: 6 -country: Turkey -role: Air-to-Air Refueling -aircraft: KC-135 Stratotanker -livery: TurAF Standard -mission_types: - - Refueling diff --git a/resources/squadrons/KC-135MPRS/340th EARS.yaml b/resources/squadrons/KC-135MPRS/340th EARS.yaml deleted file mode 100644 index 762bee1c2..000000000 --- a/resources/squadrons/KC-135MPRS/340th EARS.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: 340th Expeditionary Air Refueling Squadron -nickname: Pythons -female_pilot_percentage: 6 -country: USA -role: Air-to-Air Refueling -aircraft: KC-135 Stratotanker MPRS -mission_types: - - Refueling diff --git a/resources/squadrons/Mi-24/SAAF 765th Sqn.yaml b/resources/squadrons/Mi-24/SAAF 765th Sqn.yaml deleted file mode 100644 index c15ea350f..000000000 --- a/resources/squadrons/Mi-24/SAAF 765th Sqn.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 765th Squadron -nickname: 765th -female_pilot_percentage: 0 -country: Syria -role: Attack Helicopter -aircraft: Mi-24P Hind-F -livery: "SyAAF" -mission_types: - - CAS - - BAI - - Transport - - Air Assault diff --git a/resources/squadrons/Mi-24/SAAF 766th Sqn.yaml b/resources/squadrons/Mi-24/SAAF 766th Sqn.yaml deleted file mode 100644 index aecd10fce..000000000 --- a/resources/squadrons/Mi-24/SAAF 766th Sqn.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 766th Squadron -nickname: 766th -female_pilot_percentage: 0 -country: Syria -role: Attack Helicopter -aircraft: Mi-24V Hind-E -livery: "standard" -mission_types: - - CAS - - BAI - - Transport - - Air Assault diff --git a/resources/squadrons/Mi-8/SAAF 253th Sqn.yaml b/resources/squadrons/Mi-8/SAAF 253th Sqn.yaml deleted file mode 100644 index 0c4297dc0..000000000 --- a/resources/squadrons/Mi-8/SAAF 253th Sqn.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 253th Squadron -nickname: 253th -female_pilot_percentage: 0 -country: Syria -role: Transport Helicopter -aircraft: Mi-8MTV2 Hip -livery: "BP_RS01" -mission_types: - - Transport - - CAS - - BAI - - Air Assault \ No newline at end of file diff --git a/resources/squadrons/Mi-8/SAAF 255th Sqn.yaml b/resources/squadrons/Mi-8/SAAF 255th Sqn.yaml deleted file mode 100644 index 1a2a19cda..000000000 --- a/resources/squadrons/Mi-8/SAAF 255th Sqn.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 255th Squadron -nickname: 255th -female_pilot_percentage: 0 -country: Syria -role: Transport Helicopter -aircraft: Mi-8MTV2 Hip -livery: "BP_RS01" -mission_types: - - Transport - - CAS - - BAI - - Air Assault diff --git a/resources/squadrons/Mig-21/DPRK 34th Sqn.yaml b/resources/squadrons/Mig-21/DPRK 34th Sqn.yaml deleted file mode 100644 index 857668e7d..000000000 --- a/resources/squadrons/Mig-21/DPRK 34th Sqn.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: 34th Squadron -nickname: 34th -country: North Korea -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "dprk - 2014 - 34" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/DPRK 42nd Sqn.yaml b/resources/squadrons/Mig-21/DPRK 42nd Sqn.yaml deleted file mode 100644 index 9623b872f..000000000 --- a/resources/squadrons/Mig-21/DPRK 42nd Sqn.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: 42nd Squadron -nickname: 42nd -country: North Korea -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "dprk - 2016 - 42" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/IRIAF 51 TFS.yaml b/resources/squadrons/Mig-21/IRIAF 51 TFS.yaml deleted file mode 100644 index 25bb9dff9..000000000 --- a/resources/squadrons/Mig-21/IRIAF 51 TFS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: IRIAF 51 TFS -nickname: 51 TFS -country: Iran -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "iran - standard" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep diff --git a/resources/squadrons/Mig-21/IRIAF 52 TFS.yaml b/resources/squadrons/Mig-21/IRIAF 52 TFS.yaml deleted file mode 100644 index 9de19064a..000000000 --- a/resources/squadrons/Mig-21/IRIAF 52 TFS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: IRIAF 52 TFS -nickname: 52 TFS -country: Iran -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "iran - standard" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/IRIAF 53 TFS.yaml b/resources/squadrons/Mig-21/IRIAF 53 TFS.yaml deleted file mode 100644 index 1f17056f2..000000000 --- a/resources/squadrons/Mig-21/IRIAF 53 TFS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: IRIAF 53 TFS -nickname: 53 TFS -country: Iran -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "iran - standard" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/SAAF 679th Sqn.yaml b/resources/squadrons/Mig-21/SAAF 679th Sqn.yaml deleted file mode 100644 index 68076171d..000000000 --- a/resources/squadrons/Mig-21/SAAF 679th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 679th Squadron -nickname: 679th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "Syria (2)" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/SAAF 680th Sqn.yaml b/resources/squadrons/Mig-21/SAAF 680th Sqn.yaml deleted file mode 100644 index 90271f63d..000000000 --- a/resources/squadrons/Mig-21/SAAF 680th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 680th Squadron -nickname: 680th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "Syria (2)" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/SAAF 825th Sqn.yaml b/resources/squadrons/Mig-21/SAAF 825th Sqn.yaml deleted file mode 100644 index 50319ce33..000000000 --- a/resources/squadrons/Mig-21/SAAF 825th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 825th Squadron -nickname: 825th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "Syria (1)" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/SAAF 8th Sqn.yaml b/resources/squadrons/Mig-21/SAAF 8th Sqn.yaml deleted file mode 100644 index a529e577c..000000000 --- a/resources/squadrons/Mig-21/SAAF 8th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 8th Squadron -nickname: 8th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "Syria (1)" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-21/VPAF - 921st Sao Do.yaml b/resources/squadrons/Mig-21/VPAF - 921st Sao Do.yaml deleted file mode 100644 index 10a9388cf..000000000 --- a/resources/squadrons/Mig-21/VPAF - 921st Sao Do.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 921st Fighter Regiment -nickname: 921st -female_pilot_percentage: 0 -country: Vietnam -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VPAF - 921st Sao Do - 5040" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep \ No newline at end of file diff --git a/resources/squadrons/Mig-21/VPAF - 927th Fighter Regiment Metal.yaml b/resources/squadrons/Mig-21/VPAF - 927th Fighter Regiment Metal.yaml deleted file mode 100644 index 893853262..000000000 --- a/resources/squadrons/Mig-21/VPAF - 927th Fighter Regiment Metal.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: VPAF - 927th Fighter Regiment Intercept -nickname: 927th Int -female_pilot_percentage: 0 -country: Vietnam -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VPAF - 927th Fighter Regiment Metal" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep \ No newline at end of file diff --git a/resources/squadrons/Mig-21/VPAF - 927th Lam Son - 6122.yaml b/resources/squadrons/Mig-21/VPAF - 927th Lam Son - 6122.yaml deleted file mode 100644 index 3fef067fc..000000000 --- a/resources/squadrons/Mig-21/VPAF - 927th Lam Son - 6122.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: VPAF - 927th Fighter Regiment Strike -nickname: 927th Strike -female_pilot_percentage: 0 -country: Vietnam -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VPAF - 927th Lam Son - 6122" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep \ No newline at end of file diff --git a/resources/squadrons/Mig-21/VVS 115th GvIAP Fighter Regiment.yaml b/resources/squadrons/Mig-21/VVS 115th GvIAP Fighter Regiment.yaml deleted file mode 100644 index 6061232be..000000000 --- a/resources/squadrons/Mig-21/VVS 115th GvIAP Fighter Regiment.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 115th GvIAP Fighter Regiment -nickname: 115th -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VVS - 115 GvIAP" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep \ No newline at end of file diff --git a/resources/squadrons/Mig-21/VVS 116th CBP Training Center.yaml b/resources/squadrons/Mig-21/VVS 116th CBP Training Center.yaml deleted file mode 100644 index 82598bfe8..000000000 --- a/resources/squadrons/Mig-21/VVS 116th CBP Training Center.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 116th CBP -nickname: 116th -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VVS - 116 CBP" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep diff --git a/resources/squadrons/Mig-21/VVS 185th GvIAP Fighter Regiment.yaml b/resources/squadrons/Mig-21/VVS 185th GvIAP Fighter Regiment.yaml deleted file mode 100644 index d6762aabe..000000000 --- a/resources/squadrons/Mig-21/VVS 185th GvIAP Fighter Regiment.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 185th GvIAP Fighter Regiment -nickname: 185th GvIAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VVS - 185th GvIAP" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep diff --git a/resources/squadrons/Mig-21/VVS 234th GvIAP Fighter Regiment.yaml b/resources/squadrons/Mig-21/VVS 234th GvIAP Fighter Regiment.yaml deleted file mode 100644 index 6d15681dc..000000000 --- a/resources/squadrons/Mig-21/VVS 234th GvIAP Fighter Regiment.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 234th GvIAP Fighter Regiment -nickname: 234th GvIAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-21bis Fishbed-N -livery: "VVS - 234 GvIAP" -mission_types: - - BARCAP - - TARCAP - - CAS - - Strike - - Escort - - Intercept - - Fighter sweep diff --git a/resources/squadrons/Mig-23/SAAF 678th Sqn.yaml b/resources/squadrons/Mig-23/SAAF 678th Sqn.yaml deleted file mode 100644 index 7bd815efc..000000000 --- a/resources/squadrons/Mig-23/SAAF 678th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 678th Squadron -nickname: 678th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-23MLD Flogger-K -livery: "af standard-3 (worn-out)" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-25/SAAF 1st Sqn.yaml b/resources/squadrons/Mig-25/SAAF 1st Sqn.yaml deleted file mode 100644 index 8a59004ea..000000000 --- a/resources/squadrons/Mig-25/SAAF 1st Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 1st Squadron -nickname: 1st -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-25PD Foxbat-E -livery: "af standard" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/Russia VVS 115th GvIAP.yaml b/resources/squadrons/Mig-29/Russia VVS 115th GvIAP.yaml deleted file mode 100644 index cda2c3fb9..000000000 --- a/resources/squadrons/Mig-29/Russia VVS 115th GvIAP.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 115th Guards Aviation Regiment -nickname: 115th GvIAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "115 GvIAP_Termez" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/Russia VVS 28th GvIAP.yaml b/resources/squadrons/Mig-29/Russia VVS 28th GvIAP.yaml deleted file mode 100644 index 29bd2ab26..000000000 --- a/resources/squadrons/Mig-29/Russia VVS 28th GvIAP.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 28th Guards Aviation Regiment -nickname: 28th GvIAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "28 GvIAP_Andreapol" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/Russia VVS 31st GvIAP.yaml b/resources/squadrons/Mig-29/Russia VVS 31st GvIAP.yaml deleted file mode 100644 index 019b6c6c5..000000000 --- a/resources/squadrons/Mig-29/Russia VVS 31st GvIAP.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 31st Guards Aviation Regiment -nickname: 31st GvIAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "31 GvIAP_Zernograd" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/Russia VVS 773rd IAP.yaml b/resources/squadrons/Mig-29/Russia VVS 773rd IAP.yaml deleted file mode 100644 index 36e4c2d7a..000000000 --- a/resources/squadrons/Mig-29/Russia VVS 773rd IAP.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 773rd Aviation Regiment -nickname: 773rd IAP -female_pilot_percentage: 0 -country: Russia -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "773 IAP_Damgarten" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/SAAF 697th Sqn.yaml b/resources/squadrons/Mig-29/SAAF 697th Sqn.yaml deleted file mode 100644 index c67413145..000000000 --- a/resources/squadrons/Mig-29/SAAF 697th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 697th Squadron -nickname: 697th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "ERAF" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mig-29/SAAF 699th Sqn.yaml b/resources/squadrons/Mig-29/SAAF 699th Sqn.yaml deleted file mode 100644 index 83e1f2c6f..000000000 --- a/resources/squadrons/Mig-29/SAAF 699th Sqn.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 699th Squadron -nickname: 699th -female_pilot_percentage: 0 -country: Syria -role: Air Superiority Fighter -aircraft: MiG-29S Fulcrum-C -livery: "ERAF" -mission_types: - - BARCAP - - TARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/Mirage-F1/AAE Squadron 1-5 Vendee.yaml b/resources/squadrons/Mirage-F1/AAE Squadron 1-5 Vendee.yaml deleted file mode 100644 index 49f77f49a..000000000 --- a/resources/squadrons/Mirage-F1/AAE Squadron 1-5 Vendee.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Escadron de Chasse 1/5 Vendee -nickname: Vendee -female_pilot_percentage: 5 -country: France -role: Fighter -aircraft: Mirage-F1C-200 -livery: EC 1 5 Vendee BA Orange-Cariat -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/AAE Squadron 3-33 Lorraine.yaml b/resources/squadrons/Mirage-F1/AAE Squadron 3-33 Lorraine.yaml deleted file mode 100644 index 647433b27..000000000 --- a/resources/squadrons/Mirage-F1/AAE Squadron 3-33 Lorraine.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Escadron de Chasse 3/33 Lorraine -nickname: Lorraine -female_pilot_percentage: 10 -country: France -role: Multirole Fighter -aircraft: Mirage-F1CT -livery: EC 3 33 Lorraine -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/IQAF 89th Squadron.yaml b/resources/squadrons/Mirage-F1/IQAF 89th Squadron.yaml deleted file mode 100644 index 73ae7227a..000000000 --- a/resources/squadrons/Mirage-F1/IQAF 89th Squadron.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: No. 89 Squadron -nickname: Saddam's Guards -female_pilot_percentage: 0 -country: Iraq -role: Multirole Fighter -aircraft: Mirage-F1EQ -livery: Iraq Air Force -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/IQAF 91st Squadron.yaml b/resources/squadrons/Mirage-F1/IQAF 91st Squadron.yaml deleted file mode 100644 index 526e6433c..000000000 --- a/resources/squadrons/Mirage-F1/IQAF 91st Squadron.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: No. 91 Squadron -nickname: Iraq's Angles -female_pilot_percentage: 0 -country: Iraq -role: Multirole Fighter -aircraft: Mirage-F1EQ -livery: Iraq Air Force Blue Scheme -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/SASF 14th Wing - 141st Squadron.yaml b/resources/squadrons/Mirage-F1/SASF 14th Wing - 141st Squadron.yaml deleted file mode 100644 index cfc8ded98..000000000 --- a/resources/squadrons/Mirage-F1/SASF 14th Wing - 141st Squadron.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: 14th Wing, 141st Squadron -nickname: Ángeles -female_pilot_percentage: 8 -country: Spain -role: Fighter -aircraft: Mirage-F1CE -livery: ALA 14 Camu Lagarto 1975-1990 SQ 141 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/SASF 14th Wing - 142nd Squadron.yaml b/resources/squadrons/Mirage-F1/SASF 14th Wing - 142nd Squadron.yaml deleted file mode 100644 index 8ae91dbcf..000000000 --- a/resources/squadrons/Mirage-F1/SASF 14th Wing - 142nd Squadron.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: 14th Wing, 142nd Squadron -nickname: Tigres Voladores -female_pilot_percentage: 3 -country: Spain -role: Fighter -aircraft: Mirage-F1CE -livery: ALA 14 Camu Lagarto 1975-1990 SQ 142 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/SASF 14th Wing - NATO.yaml b/resources/squadrons/Mirage-F1/SASF 14th Wing - NATO.yaml deleted file mode 100644 index ccdae6819..000000000 --- a/resources/squadrons/Mirage-F1/SASF 14th Wing - NATO.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: 14th Wing, NATO -nickname: Spaniards -female_pilot_percentage: 5 -country: Spain -role: Fighter -aircraft: Mirage-F1M-EE -livery: ALA 14 NATO Skin 1 (M-EE) -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Mirage-F1/SASF 46th Wing - 462nd Squadron.yaml b/resources/squadrons/Mirage-F1/SASF 46th Wing - 462nd Squadron.yaml deleted file mode 100644 index 78ae45e50..000000000 --- a/resources/squadrons/Mirage-F1/SASF 46th Wing - 462nd Squadron.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: 46th Wing, 462nd Squadron -nickname: Ángeles -female_pilot_percentage: 7 -country: Spain -role: Fighter -aircraft: Mirage-F1BE -livery: ALA 46 Camu Lagarto 1975-1990 Gando SQ 462 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/MosquitoFBMkVI/no_21_squadron_raf.yaml b/resources/squadrons/MosquitoFBMkVI/no_21_squadron_raf.yaml deleted file mode 100644 index 02cd4cdd8..000000000 --- a/resources/squadrons/MosquitoFBMkVI/no_21_squadron_raf.yaml +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: RAF, No. 21 Squadron -nickname: No. 21 -female_pilot_percentage: 0 -country: UK -role: Fighter Bomber -aircraft: MosquitoFBMkVI -livery: RAF -mission_types: - - CAS - - Strike - - Anti-ship - - OCA/Aircraft - - Intercept - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/OV-10A Bronco/19th TASS.yaml b/resources/squadrons/OV-10A Bronco/19th TASS.yaml deleted file mode 100644 index 1fc716086..000000000 --- a/resources/squadrons/OV-10A Bronco/19th TASS.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: 19th TASS -nickname: 19th TACTICAL AIR SUPPORT SQUADRON -female_pilot_percentage: 0 -country: USA -role: COIN / FAC /Light Attack -aircraft: OV-10A Bronco -livery: 19TH TACTICAL AIR SUPPORT SQUADRON -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/OV-10A Bronco/20th TASS.yaml b/resources/squadrons/OV-10A Bronco/20th TASS.yaml deleted file mode 100644 index a9ad2b706..000000000 --- a/resources/squadrons/OV-10A Bronco/20th TASS.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: 20th TASS -nickname: 20th TACTICAL AIR SUPPORT SQUADRON -female_pilot_percentage: 0 -country: USA -role: COIN / FAC /Light Attack -aircraft: OV-10A Bronco -livery: 20TH TACTICAL AIR SUPPORT SQUADRON -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/OV-10A Bronco/VAL-4.yaml b/resources/squadrons/OV-10A Bronco/VAL-4.yaml deleted file mode 100644 index e1ca0de22..000000000 --- a/resources/squadrons/OV-10A Bronco/VAL-4.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: VAL-4 -nickname: Black Ponies -female_pilot_percentage: 0 -country: USA -role: Light Attack -aircraft: OV-10A Bronco -livery: VAL-4 104 -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/OV-10A Bronco/VMO-2.yaml b/resources/squadrons/OV-10A Bronco/VMO-2.yaml deleted file mode 100644 index 4fb4a7043..000000000 --- a/resources/squadrons/OV-10A Bronco/VMO-2.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: VMO-2 -nickname: The Angry Two -female_pilot_percentage: 0 -country: USA -role: COIN / FAC /Light Attack -aircraft: OV-10A Bronco -livery: VMO-2 -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/OV-10A Bronco/VMO-5.yaml b/resources/squadrons/OV-10A Bronco/VMO-5.yaml deleted file mode 100644 index bdd24400c..000000000 --- a/resources/squadrons/OV-10A Bronco/VMO-5.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: VMO-5 -nickname: Black Aces -female_pilot_percentage: 0 -country: USA -role: COIN / FAC /Light Attack -aircraft: OV-10A Bronco -livery: VMO-5 UV -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/OV-10A Bronco/VS-41 Shamrocks.yaml b/resources/squadrons/OV-10A Bronco/VS-41 Shamrocks.yaml deleted file mode 100644 index 3fcf1871a..000000000 --- a/resources/squadrons/OV-10A Bronco/VS-41 Shamrocks.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: VS-41 -nickname: Shamrocks -female_pilot_percentage: 0 -country: USA -role: COIN / FAC /Light Attack -aircraft: OV-10A Bronco -livery: VS-41 Shamrocks -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/S-3B/VS-35.yaml b/resources/squadrons/S-3B/VS-35.yaml deleted file mode 100644 index c0455b341..000000000 --- a/resources/squadrons/S-3B/VS-35.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: VS-35 -nickname: Blue Wolves -female_pilot_percentage: 0 -country: USA -role: Carrier-based Attack -aircraft: S-3B Viking -livery: usaf standard -mission_types: - - Anti-ship - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/S-3B/VS-35F.yaml b/resources/squadrons/S-3B/VS-35F.yaml deleted file mode 100644 index 0898c2f66..000000000 --- a/resources/squadrons/S-3B/VS-35F.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: VS-35 (Tanker) -nickname: Blue Wolves -female_pilot_percentage: 0 -country: USA -role: Tanker -aircraft: S-3B Tanker -livery: NAVY Standard -mission_types: - - Refueling diff --git a/resources/squadrons/SH-60B/HSM-40.yaml b/resources/squadrons/SH-60B/HSM-40.yaml deleted file mode 100644 index bb7e54f9e..000000000 --- a/resources/squadrons/SH-60B/HSM-40.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: HSM-40 -nickname: Airwolves -female_pilot_percentage: 0 -country: USA -role: Transport/Anti-Ship -aircraft: SH-60B Seahawk -livery: standard -mission_types: - - Transport - - Anti-ship - - Air Assault diff --git a/resources/squadrons/SpitfireLFMkIX/no_145_squadron_raf.yaml b/resources/squadrons/SpitfireLFMkIX/no_145_squadron_raf.yaml deleted file mode 100644 index bd921f0c2..000000000 --- a/resources/squadrons/SpitfireLFMkIX/no_145_squadron_raf.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: RAF, No. 145 Squadron -nickname: No. 145 -female_pilot_percentage: 0 -country: UK -role: Fighter -aircraft: Spitfire LF Mk IX -livery: RAF, No. 145 Squadron -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/SpitfireLFMkIX/no_16_squadron_raf.yaml b/resources/squadrons/SpitfireLFMkIX/no_16_squadron_raf.yaml deleted file mode 100644 index 23ba6f8a1..000000000 --- a/resources/squadrons/SpitfireLFMkIX/no_16_squadron_raf.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: RAF, No. 16 Squadron -nickname: No. 16 -female_pilot_percentage: 0 -country: UK -role: Fighter -aircraft: Spitfire LF Mk IX -livery: RAF, No. 16 Squadron -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/SpitfireLFMkIXCW/no_126_squadron_raf.yaml b/resources/squadrons/SpitfireLFMkIXCW/no_126_squadron_raf.yaml deleted file mode 100644 index 2c89d965e..000000000 --- a/resources/squadrons/SpitfireLFMkIXCW/no_126_squadron_raf.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: RAF, No. 126 Squadron -nickname: Harrowbeer -female_pilot_percentage: 0 -country: UK -role: Fighter -aircraft: Spitfire LF Mk IX (Clipped Wings) -livery: RAF, No. 126 Squadron, Harrowbeer -mission_types: - - CAS - - Escort - - Intercept - - OCA/Aircraft - - Fighter sweep - - BARCAP - - TARCAP diff --git a/resources/squadrons/Strike Eagle/335th FS.yaml b/resources/squadrons/Strike Eagle/335th FS.yaml deleted file mode 100644 index e0ddb8fbf..000000000 --- a/resources/squadrons/Strike Eagle/335th FS.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -name: 335th FS -nickname: Chiefs -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle -livery: 335th Fighter SQN (SJ) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Strike Eagle/492nd FS.yaml b/resources/squadrons/Strike Eagle/492nd FS.yaml deleted file mode 100644 index 29d4b57a1..000000000 --- a/resources/squadrons/Strike Eagle/492nd FS.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 492nd FS -nickname: Bolars -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-15E Strike Eagle -livery: 492d Fighter SQN (LN) -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/Strike Eagle/IAF 69th Sqn.yaml b/resources/squadrons/Strike Eagle/IAF 69th Sqn.yaml deleted file mode 100644 index ab736b185..000000000 --- a/resources/squadrons/Strike Eagle/IAF 69th Sqn.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 69th Squadron -nickname: Hammers -female_pilot_percentage: 6 -country: Israel -role: Strike Fighter -aircraft: F-15E Strike Eagle -livery: IDF No 69 Hammers Squadron -mission_types: - - BAI - - CAS - - DEAD - - OCA/Aircraft - - OCA/Runway - - Strike - diff --git a/resources/squadrons/Su-17/SAAF 677th Sqn.yaml b/resources/squadrons/Su-17/SAAF 677th Sqn.yaml deleted file mode 100644 index e2a77b53b..000000000 --- a/resources/squadrons/Su-17/SAAF 677th Sqn.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 677th Squadron -nickname: 677th -female_pilot_percentage: 0 -country: Syria -role: Bomber -aircraft: Su-17M4 Fitter-K -livery: "af standard (worn-out)" -mission_types: - - BAI - - CAS - - DEAD - - SEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Su-17/SAAF 685th Sqn.yaml b/resources/squadrons/Su-17/SAAF 685th Sqn.yaml deleted file mode 100644 index bb89e8b12..000000000 --- a/resources/squadrons/Su-17/SAAF 685th Sqn.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 685th Squadron -nickname: 685th -female_pilot_percentage: 0 -country: Syria -role: Bomber -aircraft: Su-17M4 Fitter-K -livery: "af standard (worn-out)" -mission_types: - - BAI - - CAS - - DEAD - - SEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Su-17/SAAF 827th Sqn.yaml b/resources/squadrons/Su-17/SAAF 827th Sqn.yaml deleted file mode 100644 index 516885769..000000000 --- a/resources/squadrons/Su-17/SAAF 827th Sqn.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 827th Squadron -nickname: 827th -female_pilot_percentage: 0 -country: Syria -role: Bomber -aircraft: Su-17M4 Fitter-K -livery: "af standard (worn-out)" -mission_types: - - BAI - - CAS - - DEAD - - SEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Su-24/SAAF 819th Sqn.yaml b/resources/squadrons/Su-24/SAAF 819th Sqn.yaml deleted file mode 100644 index 6e03e16bd..000000000 --- a/resources/squadrons/Su-24/SAAF 819th Sqn.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: 819th Squadron -nickname: 819th -female_pilot_percentage: 0 -country: Syria -role: Bomber -aircraft: Su-24M Fencer-D -livery: "Syrian Air Force" -mission_types: - - BAI - - CAS - - DEAD - - SEAD - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/Tornado/RAF No12 Squadron.yaml b/resources/squadrons/Tornado/RAF No12 Squadron.yaml deleted file mode 100644 index 7d4581f84..000000000 --- a/resources/squadrons/Tornado/RAF No12 Squadron.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: No. 12 Squadron -nickname: Shiny Twelve -female_pilot_percentage: 6 -country: UK -role: Strike Fighter -aircraft: Tornado GR4 -livery: HAF_341_Arrow -mission_types: - - BAI - - CAS - - DEAD - - OCA/Runway - - SEAD - - SEAD Escort - - Strike diff --git a/resources/squadrons/UH-1/HMLA-169-UH1H.yaml b/resources/squadrons/UH-1/HMLA-169-UH1H.yaml deleted file mode 100644 index 77b748c4d..000000000 --- a/resources/squadrons/UH-1/HMLA-169-UH1H.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: HMLA-169 (UH-1H) -nickname: Vipers -female_pilot_percentage: 0 -country: USA -role: Transport/Light Attack -aircraft: UH-1H Iroquois -livery: US NAVY -mission_types: - - CAS - - OCA/Aircraft - - Transport - - Air Assault diff --git a/resources/squadrons/UH-1/HMLA-269-UH1H.yaml b/resources/squadrons/UH-1/HMLA-269-UH1H.yaml deleted file mode 100644 index 155c6344a..000000000 --- a/resources/squadrons/UH-1/HMLA-269-UH1H.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: HMLA-269 (UH-1H) -nickname: Gunrunners -female_pilot_percentage: 0 -country: USA -role: Transport/Light Attack -aircraft: UH-1H Iroquois -livery: US NAVY -mission_types: - - CAS - - OCA/Aircraft - - Transport - - Air Assault diff --git a/resources/squadrons/UH-60/US Army 101st Combat Aviation Brigade.yaml b/resources/squadrons/UH-60/US Army 101st Combat Aviation Brigade.yaml deleted file mode 100644 index 4ab8f192f..000000000 --- a/resources/squadrons/UH-60/US Army 101st Combat Aviation Brigade.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 101st Combat Aviation Brigade -nickname: Bearcats -female_pilot_percentage: 0 -country: USA -role: Transport/Light Attack -aircraft: UH-60A -livery: standard -mission_types: - - CAS - - OCA/Aircraft - - Transport - - Air Assault diff --git a/resources/squadrons/globemaster/15th-Airlift.yaml b/resources/squadrons/globemaster/15th-Airlift.yaml deleted file mode 100644 index 865665830..000000000 --- a/resources/squadrons/globemaster/15th-Airlift.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -name: 15th Airlift Squadron -nickname: Global Eagles -female_pilot_percentage: 6 -country: USA -role: Airlift -aircraft: C-17A -mission_types: - - Transport diff --git a/resources/squadrons/hornet/VFA-106.yaml b/resources/squadrons/hornet/VFA-106.yaml deleted file mode 100644 index f8effee38..000000000 --- a/resources/squadrons/hornet/VFA-106.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: VFA-106 -nickname: Gladiators -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F/A-18C Hornet (Lot 20) -livery: VFA-106 high visibility -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/hornet/VFA-113.yaml b/resources/squadrons/hornet/VFA-113.yaml deleted file mode 100644 index e4a13602e..000000000 --- a/resources/squadrons/hornet/VFA-113.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: VFA-113 -nickname: Stingers -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F/A-18C Hornet (Lot 20) -livery: VFA-113 -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/hornet/VFA-192.yaml b/resources/squadrons/hornet/VFA-192.yaml deleted file mode 100644 index 1ffd8e4a4..000000000 --- a/resources/squadrons/hornet/VFA-192.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: VFA-192 -nickname: Golden Dragons -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F/A-18C Hornet (Lot 20) -livery: VFA-192 -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/hornet/VMFA-122.yaml b/resources/squadrons/hornet/VMFA-122.yaml deleted file mode 100644 index 79fdb66c3..000000000 --- a/resources/squadrons/hornet/VMFA-122.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: VMFA-122 -nickname: Werewolves -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F/A-18C Hornet (Lot 20) -livery: VMFA-122 high visibility -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/hornet/VMFA-251.yaml b/resources/squadrons/hornet/VMFA-251.yaml deleted file mode 100644 index 82344eb4e..000000000 --- a/resources/squadrons/hornet/VMFA-251.yaml +++ /dev/null @@ -1,23 +0,0 @@ ---- -name: VMFA-251 -nickname: Thunderbolts -female_pilot_percentage: 7 -country: USA -role: Strike Fighter -aircraft: F/A-18C Hornet (Lot 20) -livery: VMFA-251 high visibility -mission_types: - - Anti-ship - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/m2000-5/ADA_EscadronDeChasse_1-2_Cigognes.yaml b/resources/squadrons/m2000-5/ADA_EscadronDeChasse_1-2_Cigognes.yaml deleted file mode 100644 index fe9700624..000000000 --- a/resources/squadrons/m2000-5/ADA_EscadronDeChasse_1-2_Cigognes.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Escadron de chasse 1/2 -nickname: Cigognes -female_pilot_percentage: 6 -country: France -role: Fighter -aircraft: Mirage 2000-5 -livery: ec1_2 spa12 `cigogne a ailes ouvertes` -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/m2000-5/ADA_EscadronDeChasse_2-2_CoteDOr.yaml b/resources/squadrons/m2000-5/ADA_EscadronDeChasse_2-2_CoteDOr.yaml deleted file mode 100644 index 63bd1e4ba..000000000 --- a/resources/squadrons/m2000-5/ADA_EscadronDeChasse_2-2_CoteDOr.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Escadron de chasse 2/2 -nickname: Côte d'Or -female_pilot_percentage: 6 -country: France -role: Fighter -aircraft: Mirage 2000-5 -livery: ec2_2 `cote d'or` spa57 `mouette` -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-12_Cambresis.yaml b/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-12_Cambresis.yaml deleted file mode 100644 index 71a292148..000000000 --- a/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-12_Cambresis.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Escadron de chasse 1/12 -nickname: Cambrésis -female_pilot_percentage: 6 -country: France -role: Fighter -aircraft: Mirage 2000C -livery: Cambresis -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-30_Alsace.yaml b/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-30_Alsace.yaml deleted file mode 100644 index 166cedac7..000000000 --- a/resources/squadrons/m2000c/ADA_EscadronDeChasse_1-30_Alsace.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Escadron de chasse 1/30 -nickname: Alsace -female_pilot_percentage: 6 -country: France -role: Fighter -aircraft: Mirage 2000C -livery: AdA Alsace LF-2 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/m2000c/ADA_EscadronDeChasse_2-5_IleDeFrance.yaml b/resources/squadrons/m2000c/ADA_EscadronDeChasse_2-5_IleDeFrance.yaml deleted file mode 100644 index 9b8901576..000000000 --- a/resources/squadrons/m2000c/ADA_EscadronDeChasse_2-5_IleDeFrance.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -name: Escadron de chasse 2/5 -nickname: Île De France -female_pilot_percentage: 6 -country: France -role: Fighter -aircraft: Mirage 2000C -livery: AdA Chasse 2-5 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/m2000c/FAP_EscuadronAereo_412_Halcones.yaml b/resources/squadrons/m2000c/FAP_EscuadronAereo_412_Halcones.yaml deleted file mode 100644 index 15bc8c7ec..000000000 --- a/resources/squadrons/m2000c/FAP_EscuadronAereo_412_Halcones.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -name: Escuadrón Aéreo 412 -nickname: Halcones -country: Peru -role: Fighter -aircraft: Mirage 2000C -livery: Peru052 -mission_types: - - BARCAP - - Escort - - Intercept - - Fighter sweep - - TARCAP - - BAI - - CAS - - OCA/Aircraft - - OCA/Runway - - Strike diff --git a/resources/squadrons/sa342/ALAT_1er_RHC.yaml b/resources/squadrons/sa342/ALAT_1er_RHC.yaml deleted file mode 100644 index d547ad3b9..000000000 --- a/resources/squadrons/sa342/ALAT_1er_RHC.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: 1er régiment d'hélicoptères de combat -nickname: -female_pilot_percentage: 6 -country: France -role: Anti-Aircraft Helicopter -aircraft: SA 342M Gazelle Mistral -livery: Combat -mission_types: - - TARCAP diff --git a/resources/squadrons/sa342/ALAT_3eme_RHC.yaml b/resources/squadrons/sa342/ALAT_3eme_RHC.yaml deleted file mode 100644 index 48dc8c156..000000000 --- a/resources/squadrons/sa342/ALAT_3eme_RHC.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -name: 3ème régiment d'hélicoptères de combat -nickname: Grand 3 -female_pilot_percentage: 6 -country: France -role: Anti-Tank Helicopter -aircraft: SA 342M Gazelle -livery: Combat -mission_types: - - Anti-ship - - CAS - - OCA/Aircraft - - Strike diff --git a/resources/squadrons/sa342/ALAT_5eme_RHC.yaml b/resources/squadrons/sa342/ALAT_5eme_RHC.yaml deleted file mode 100644 index 4254413ad..000000000 --- a/resources/squadrons/sa342/ALAT_5eme_RHC.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 5ème régiment d'hélicoptères de combat -nickname: Le régiment du Béarn -female_pilot_percentage: 6 -country: France -role: Combat Helicopter -aircraft: SA 342L Gazelle -livery: Combat -mission_types: - - CAS - - OCA/Aircraft diff --git a/resources/squadrons/sa342/ALAT_DOAS.yaml b/resources/squadrons/sa342/ALAT_DOAS.yaml deleted file mode 100644 index 9bc4e677a..000000000 --- a/resources/squadrons/sa342/ALAT_DOAS.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Détachement ALAT des opérations spéciales -nickname: DOAS -female_pilot_percentage: 6 -country: France -role: Combat Helicopter -aircraft: SA342Minigun -livery: Combat -mission_types: - - CAS diff --git a/resources/squadrons/sa342/SAAF 976th Sqn.yaml b/resources/squadrons/sa342/SAAF 976th Sqn.yaml deleted file mode 100644 index dbba83382..000000000 --- a/resources/squadrons/sa342/SAAF 976th Sqn.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 976th Squadron -nickname: 976th -female_pilot_percentage: 6 -country: Syria -role: Anti-Tank Helicopter -aircraft: SA 342L Gazelle -livery: "Syria Fictional" -mission_types: - - CAS - - BAI diff --git a/resources/squadrons/sa342/SAAF 977th Sqn.yaml b/resources/squadrons/sa342/SAAF 977th Sqn.yaml deleted file mode 100644 index c1fa87e69..000000000 --- a/resources/squadrons/sa342/SAAF 977th Sqn.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 977th Squadron -nickname: 977th -female_pilot_percentage: 6 -country: Syria -role: Anti-Tank Helicopter -aircraft: SA 342L Gazelle -livery: "Syria Fictional" -mission_types: - - CAS - - BAI diff --git a/resources/squadrons/sa342/SAAF 988th Sqn.yaml b/resources/squadrons/sa342/SAAF 988th Sqn.yaml deleted file mode 100644 index 6c0ab7285..000000000 --- a/resources/squadrons/sa342/SAAF 988th Sqn.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 988th Squadron -nickname: 988th -female_pilot_percentage: 6 -country: Syria -role: Anti-Tank Helicopter -aircraft: SA 342M Gazelle -livery: "Syria Fictional" -mission_types: - - CAS - - BAI diff --git a/resources/squadrons/sa342/SAAF 989th Sqn.yaml b/resources/squadrons/sa342/SAAF 989th Sqn.yaml deleted file mode 100644 index 78e666a2f..000000000 --- a/resources/squadrons/sa342/SAAF 989th Sqn.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -name: 989th Squadron -nickname: 989th -female_pilot_percentage: 6 -country: Syria -role: Anti-Tank Helicopter -aircraft: SA 342M Gazelle -livery: "Syria Fictional" -mission_types: - - CAS - - BAI diff --git a/resources/squadrons/viper/191-Filo.yaml b/resources/squadrons/viper/191-Filo.yaml deleted file mode 100644 index 6d276de7e..000000000 --- a/resources/squadrons/viper/191-Filo.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 191. Filo -nickname: Kobra -female_pilot_percentage: 6 -country: Turkey -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: THK_191_Filo -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 335 Tiger Squadron.yaml b/resources/squadrons/viper/HAF 335 Tiger Squadron.yaml deleted file mode 100644 index 43b19d128..000000000 --- a/resources/squadrons/viper/HAF 335 Tiger Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 335 Squadron -nickname: Tiger -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_335_Tiger -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 336 Olympus Squadron.yaml b/resources/squadrons/viper/HAF 336 Olympus Squadron.yaml deleted file mode 100644 index 76a2934dd..000000000 --- a/resources/squadrons/viper/HAF 336 Olympus Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 336 Squadron -nickname: Olympus -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_336_Olympus -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 337 Ghost Squadron.yaml b/resources/squadrons/viper/HAF 337 Ghost Squadron.yaml deleted file mode 100644 index 423e8bb18..000000000 --- a/resources/squadrons/viper/HAF 337 Ghost Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 337 Squadron -nickname: Ghost -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_337_Ghost -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 340 Fox Squadron.yaml b/resources/squadrons/viper/HAF 340 Fox Squadron.yaml deleted file mode 100644 index d320a135e..000000000 --- a/resources/squadrons/viper/HAF 340 Fox Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 340 Squadron -nickname: Fox -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_340_Fox -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 341 Arrow Squadron.yaml b/resources/squadrons/viper/HAF 341 Arrow Squadron.yaml deleted file mode 100644 index 576c6a1ed..000000000 --- a/resources/squadrons/viper/HAF 341 Arrow Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 341 Squadron -nickname: Arrow -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_341_Arrow -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 343 Star Squadron.yaml b/resources/squadrons/viper/HAF 343 Star Squadron.yaml deleted file mode 100644 index 77cdc88ab..000000000 --- a/resources/squadrons/viper/HAF 343 Star Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 343 Squadron -nickname: Star -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_343_Star -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 346 Jason Squadron.yaml b/resources/squadrons/viper/HAF 346 Jason Squadron.yaml deleted file mode 100644 index a3ab2f83d..000000000 --- a/resources/squadrons/viper/HAF 346 Jason Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 346 Squadron -nickname: Jason -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_346_Jason -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF 347 Perseus Squadron.yaml b/resources/squadrons/viper/HAF 347 Perseus Squadron.yaml deleted file mode 100644 index 1b112d06e..000000000 --- a/resources/squadrons/viper/HAF 347 Perseus Squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 347 Squadron -nickname: Perseus -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_347_Perseus -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/HAF_330_Thunder_squadron.yaml b/resources/squadrons/viper/HAF_330_Thunder_squadron.yaml deleted file mode 100644 index 8ae79ae7a..000000000 --- a/resources/squadrons/viper/HAF_330_Thunder_squadron.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 330 Squadron -nickname: Thunder -female_pilot_percentage: 6 -country: Greece -role: Multirole Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: HAF_ 330_Thunder -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/IAF 101st Sqn.yaml b/resources/squadrons/viper/IAF 101st Sqn.yaml deleted file mode 100644 index 333ace45a..000000000 --- a/resources/squadrons/viper/IAF 101st Sqn.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 101st Squadron -nickname: First Fighter -female_pilot_percentage: 6 -country: Israel -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: IAF_101st_squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/IAF 110th Sqn.yaml b/resources/squadrons/viper/IAF 110th Sqn.yaml deleted file mode 100644 index 0bb484a4e..000000000 --- a/resources/squadrons/viper/IAF 110th Sqn.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 110th Squadron -nickname: Knights of the North -female_pilot_percentage: 6 -country: Israel -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: IAF_110th_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/IAF 117th Sqn.yaml b/resources/squadrons/viper/IAF 117th Sqn.yaml deleted file mode 100644 index 931e44990..000000000 --- a/resources/squadrons/viper/IAF 117th Sqn.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 117th Squadron -nickname: First Jet -female_pilot_percentage: 6 -country: Israel -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: IAF_117th_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 132nd WG.yaml b/resources/squadrons/viper/USAF 132nd WG.yaml deleted file mode 100644 index 04614d294..000000000 --- a/resources/squadrons/viper/USAF 132nd WG.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 132nd FW -nickname: Hawkeyes -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 132nd_Wing _Iowa_ANG -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 13th FS.yaml b/resources/squadrons/viper/USAF 13th FS.yaml deleted file mode 100644 index 4268c340f..000000000 --- a/resources/squadrons/viper/USAF 13th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 13th FS -nickname: Panthers -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 13th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 14th FS.yaml b/resources/squadrons/viper/USAF 14th FS.yaml deleted file mode 100644 index 681c79625..000000000 --- a/resources/squadrons/viper/USAF 14th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 14th FS -nickname: Samurais -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 14th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 152nd FS.yaml b/resources/squadrons/viper/USAF 152nd FS.yaml deleted file mode 100644 index ce1682b8f..000000000 --- a/resources/squadrons/viper/USAF 152nd FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 152nd FS -nickname: Las Vaqueros -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 152nd_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 174th FS.yaml b/resources/squadrons/viper/USAF 174th FS.yaml deleted file mode 100644 index 8778a4cf1..000000000 --- a/resources/squadrons/viper/USAF 174th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 174th FS -nickname: Bulldogs -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 174th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 179th FS.yaml b/resources/squadrons/viper/USAF 179th FS.yaml deleted file mode 100644 index 1f82e509c..000000000 --- a/resources/squadrons/viper/USAF 179th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 179th FS -nickname: Bulldogs -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 179th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 22nd FS.yaml b/resources/squadrons/viper/USAF 22nd FS.yaml deleted file mode 100644 index 97979b549..000000000 --- a/resources/squadrons/viper/USAF 22nd FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 22nd FS -nickname: Stingers -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 22nd_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 23rd FS.yaml b/resources/squadrons/viper/USAF 23rd FS.yaml deleted file mode 100644 index cf1174114..000000000 --- a/resources/squadrons/viper/USAF 23rd FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 23rd FS -nickname: Fighting Hawks -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 23rd_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 36th FS.yaml b/resources/squadrons/viper/USAF 36th FS.yaml deleted file mode 100644 index 07397dacb..000000000 --- a/resources/squadrons/viper/USAF 36th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 36th FS -nickname: Flying Fiends -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 36th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 480th FS.yaml b/resources/squadrons/viper/USAF 480th FS.yaml deleted file mode 100644 index 8280c6844..000000000 --- a/resources/squadrons/viper/USAF 480th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 480th FS -nickname: Warhawks -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 480th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 522nd FS.yaml b/resources/squadrons/viper/USAF 522nd FS.yaml deleted file mode 100644 index ad779f63b..000000000 --- a/resources/squadrons/viper/USAF 522nd FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 522nd FS -nickname: Fireballs -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 522nd_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 55th FS.yaml b/resources/squadrons/viper/USAF 55th FS.yaml deleted file mode 100644 index 4ab3c56db..000000000 --- a/resources/squadrons/viper/USAF 55th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 55th FS -nickname: Fifty Fifth -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 55th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 77th FS.yaml b/resources/squadrons/viper/USAF 77th FS.yaml deleted file mode 100644 index d94f2fb97..000000000 --- a/resources/squadrons/viper/USAF 77th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 77th FS -nickname: Gamblers -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 77th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 79th FS.yaml b/resources/squadrons/viper/USAF 79th FS.yaml deleted file mode 100644 index 7bc89d041..000000000 --- a/resources/squadrons/viper/USAF 79th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 79th FS -nickname: Tigers -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 79th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/squadrons/viper/USAF 80th FS.yaml b/resources/squadrons/viper/USAF 80th FS.yaml deleted file mode 100644 index 9ce08965b..000000000 --- a/resources/squadrons/viper/USAF 80th FS.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: 80th FS -nickname: Headhunters -female_pilot_percentage: 6 -country: USA -role: Strike Fighter -aircraft: F-16CM Fighting Falcon (Block 50) -livery: 80th_Fighter_Squadron -mission_types: - - BAI - - BARCAP - - CAS - - DEAD - - Escort - - Intercept - - OCA/Aircraft - - OCA/Runway - - SEAD - - SEAD Escort - - Strike - - Fighter sweep - - TARCAP diff --git a/resources/stylesheets/check-hover.png b/resources/stylesheets/check-hover.png deleted file mode 100644 index 71fd2ad56..000000000 Binary files a/resources/stylesheets/check-hover.png and /dev/null differ diff --git a/resources/stylesheets/check.png b/resources/stylesheets/check.png deleted file mode 100644 index e1b612b3a..000000000 Binary files a/resources/stylesheets/check.png and /dev/null differ diff --git a/resources/stylesheets/chevron-down.png b/resources/stylesheets/chevron-down.png deleted file mode 100644 index 186aa21ee..000000000 Binary files a/resources/stylesheets/chevron-down.png and /dev/null differ diff --git a/resources/stylesheets/chevron-up.png b/resources/stylesheets/chevron-up.png deleted file mode 100644 index 8eb856b3d..000000000 Binary files a/resources/stylesheets/chevron-up.png and /dev/null differ diff --git a/resources/stylesheets/style-dcs.css b/resources/stylesheets/style-dcs.css deleted file mode 100644 index 8ef557717..000000000 --- a/resources/stylesheets/style-dcs.css +++ /dev/null @@ -1,649 +0,0 @@ -/*ui theme based on dcs*/ - - -/* -colors - -Backgrounds -blue ------------------------ #2D3E50 -dark blue ------------------- #1D2731 -med/grey/blue --------------- #435466 -dark grey ------------------- #4E5760 -button blue/grey gradient --- qlineargradient(x1:0, y1:0, x2:1, y2:1,stop:0 #A4B3B9, stop:1 #85989D); -button green gradient --- qlineargradient(x1:0, y1:0, x2:1, y2:1,stop:0 #82A466, stop:1 #5C863F); - -Text -white text ------------------- #ffffff -blue text -------------------- #3592C4 -grey text -------------------- #B7C0C6 - -*/ - -/* - * Makes all message box text selectable. - * https://stackoverflow.com/a/32595502/632035 - */ -QMessageBox { - messagebox-text-interaction-flags: 5; -} - -/*QMenuBar*/ -QMenuBar { - spacing: 2px; /* spacing between menu bar items */ - border-bottom:none; -} - -QMenuBar::item { - padding: 4px 10px; - background: transparent; - border-radius: 2px; - margin: 4px 0; -} - -QMenuBar::item:selected { /* when selected using mouse or keyboard */ - background: #1D2731; -} - -QMenuBar::item:pressed { - background: #1D2731; -} - -QToolButton:checked { - border-color: #435466; - background: #14202B; -} - -QToolButton:hover { - background: #536476; -} - -QToolBar::separator { - background:white; - width:1px; - height:1px; -} - -QToolBar QToolButton { - font: bold 18px; -} - -QMenu::item:selected { - background: #435466; -} - -QScrollBar:horizontal { - background: #435466; -} -QScrollBar:vertical { - background: #435466; -} - -QLabel{ -font-weight:normal; -text-align:right; -} - - -/*QWidget*/ -QWidget { - background-color: #2D3E50; - color:white; -} - - -/*QLiberationWindow*/ -QLiberationWindow{ - background-color: #2D3E50; - color:white; -} - -/*QTopPanel*/ -QTopPanel, -QTopPanel * { - background-color: #1D2731; - color: #B7C0C6; - font-size: 12px; - font-weight: bold; -} - -/*QPushButton*/ -QPushButton { - background: qlineargradient(x1:0, y1:0, x2:1, y2:1,stop:0 #A4B3B9, stop:1 #85989D); - border: 1px solid #97A9A9; - color:#fff; - padding: 6px 10px; - border-radius:2px; -} - -QPushButton:hover { - background: #6c7b7f; -} - -/*btn-primary*/ -QPushButton[style="btn-primary"]{ - background: qlineargradient(x1:0, y1:0, x2:1, y2:1,stop:0 #A4B3B9, stop:1 #85989D); - border: 1px solid #97A9A9; - color:#fff; - padding: 6px; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; -} -QPushButton[style="btn-primary"]:hover{ - background: #6c7b7f; -} - - -/*highlighted buttons*/ -QPushButton[style="btn-success"] , QPushButton[style="start-button"]{ - background-color:#82A466; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; -} - -QPushButton[style="start-button"]{ - padding: 8px 30px; -} - -QPushButton[style="btn-success"]:hover , QPushButton[style="start-button"]:hover{ - background:#5C863F; -} - - - -/* Buy button */ -QPushButton[style="btn-buy"]{ - background-color:#82A466; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; - margin: 0px; - padding: 2px; -} - -QPushButton[style="btn-buy"]:hover{ - background:#5C863F; -} - -/* Sell button */ -QPushButton[style="btn-sell"]{ - background-color:#9E3232; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; - margin: 0px; - padding: 2px; -} - -QPushButton[style="btn-sell"]:hover{ - background:#D84545; -} - -/* Info button */ -QPushButton[style="btn-info"]{ - background-color:#329E9E; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:lowercase; - margin: 0px; - padding: 2px; -} - -QPushButton[style="btn-info"]:hover{ - background:#45D8D8; -} - - - -QPushButton[style="btn-danger"]{ - background-color:#9E3232; - color: white; - padding: 6px; - border-radius:2px; - border: 1px solid #9E3232; -} - -QPushButton[style="btn-danger"]:hover{ - background-color:#D84545; -} - - -QPushButton[style="btn-accept"] { - background-color:#82A466; - color: white; - padding: 6px; - border-radius:2px; - border: 1px solid #82A466; -} - -QPushButton[style="btn-accept"]:hover { - background-color:#5C863F; -} - -QPushButton:disabled{ - - background:#d6d6d6; -} - -/*QLabel*/ -QLabel{ - border: none; -} - -QLabel:disabled { - color: #888888; -} - -QLabel[style="base-title"]{ - font-size: 24px; -} - -QLabel[style="budget-label"]{ - font-size: 16px; - margin-right: 20px; -} - -QLabel[style="icon-plane"]{ - background-color:#48719D; - min-height:24px; - max-width: 84px; - border: 1px solid black; - text-align:center; - color:white; -} - -QLabel[style="icon-armor"]{ - background-color:#48719D; - min-height:24px; - max-width: 64px; - border: 1px solid black; - text-align:center; - color:white; -} - -QLabel[style="BARCAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; - padding:2px 6px; -} - -QLabel[style="TARCAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; - padding:2px 6px; -} - -QLabel[style="CAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; - padding:2px 6px; -} - -QLabel[style="INTERCEPTION"]{ - border: 1px solid black; - background-color: #7752bc; - color:white; - padding:2px 6px; -} - -QLabel[style="CAS"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; - padding:2px 6px; -} - -QLabel[style="BAI"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; - padding:2px 6px; -} - -QLabel[style="ANTISHIP"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; - padding:2px 6px; -} - -QLabel[style="STRIKE"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; - padding:2px 6px; -} - -QLabel[style="DEAD"]{ - border: 1px solid black; - background-color: #cc8844; - color:white; - padding:2px 6px; -} - -QLabel[style="SEAD"]{ - border: 1px solid black; - background-color: #aa7744; - color:white; - padding:2px 6px; -} - -QLabel[style="info-element"]{ - border: 1px solid #435466; - color:white; - padding:2px 6px; -} - -QTextBrowser[style="info-desc"]{ - border: 1px solid #435466; - color:white; - padding:2px 6px; -} - -/*QGroupBox these are the sections that look like fieldsets*/ -QGroupBox { - margin-top: 1ex; /* leave space at the top for the title */ - border:1px solid #435466; - padding:5px; - margin:5px; -} - -QGroupBox[style="buy-box"]{ - padding: 0px; - margin: 0px; -} - -QGroupBox::title { - subcontrol-origin: margin; - subcontrol-position: top left; /* position at the top left */ - padding: 5px; - color: #B7C0C6; - font-weight: 800; -} - - -/*checkboxes*/ -QGroupBox::indicator , QCheckBox::indicator { - width: 14px; - height: 14px; - border: 1px solid #435466; - -} - -QGroupBox::indicator:hover , QCheckBox::indicator:hover { - border-color: #fff; - image: url(resources/stylesheets/check-hover.png); -} - -QGroupBox::indicator:unchecked , QCheckBox::indicator:unchecked { - -} - -QGroupBox::indicator:checked , QCheckBox::indicator:checked { -image: url(resources/stylesheets/check.png); -} - -QCheckBox:disabled { - color: #888888; -} -QCheckBox::indicator:disabled { - background-color: rgba(255, 255, 255, 5%); -} - - -/*QDialog*/ -QDialog{ - -} - -QListView { - border: 1px solid #14202B; - background-color: #14202B; -} - -/*QTabWidget*/ -QTabWidget::pane { /* The tab widget frame */ - border: 1px solid #1D2731; -} - -QTabWidget::tab-bar { - border: 1px solid #14202B; -} - -QTabBar::tab { - color:#5B626B; - background: #202C3A; - border-right: 1px solid #14202B; - border-left: 1px solid #14202B; - border-top: 1px solid #14202B; - min-width: 8ex; - padding: 6px 10px; -} - -QTabBar::tab:hover { - background: #1D2731; - color:#fff; -} - -QTabBar::tab:selected { - color:#3592C4; - background:#2C3E4C; -} - - - -/*QComboBox*/ -QComboBox { - border:1px solid #3B4656; - color: #fff; - padding: 4px 10px; - background: #1D2731; -} - -QComboBox::editable { - border:4px solid red; -} - -QComboBox:hover{ - border-color: #3592C4; -} - -QComboBox:disabled, QComboBox::drop-down:disabled{ - color: #B7C0C6; - background: #435466; -} - -QComboBox::drop-down { - subcontrol-origin: padding; - subcontrol-position: top right; - padding: 2px; - border:none; - color: #fff; - height: 20px; -} - -QComboBox::down-arrow { - image: url(resources/stylesheets/chevron-down.png); -} - -QComboBox QAbstractItemView { - padding: 4px; - border:1px solid #3B4656; - background: #465C74; - - } - - -/*QSpinBox number input with up down arrows*/ -QSpinBox{ - border:1px solid #3B4656; - color: #fff; - padding: 4px 10px; - background: #1D2731; - min-width:40px; -} - -QSpinBox:hover{ - border-color: #3592C4; -} - -QSpinBox::up-button , QSpinBox::down-button{ - border:none; -} - -QSpinBox::up-button{ - image: url(resources/stylesheets/chevron-up.png); -} - -QSpinBox::down-button{ - image: url(resources/stylesheets/chevron-down.png); -} - - - -QLineEdit{ - padding: 4px 10px; - border:1px solid #3B4656; - background: #465C74; - color: #fff; - margin-bottom:10px; -} - - -/*table view*/ -QHeaderView{ - background: #4B5B74; -} -QHeaderView::section { - background: #4B5B74; - padding: 4px; - border-style: none; -} - -QHeaderView::section:horizontal -{ - /*border: none;*/ - text-align:left; - background: #4B5B74; -} - -QHeaderView::section:vertical -{ - /*border: none;*/ - text-align:left; - background: #4B5B74; -} - -QTableView QTableCornerButton::section { - background: #4B5B74; -} - -/*helper modifiers*/ -*[style="no-border"] { - border:none; -} - -*[style="bordered"]{ - border: 1px solid #1D2731; -} - - -/* -QBaseMenu{ - background-color:#699245; - color:white; -} - -QWidget[style="baseMenuHeader"]{ - font-size: 24px; - font-weight: bold; - color:white; -}*/ - -QLabel[style="small"], QLabel[style="text-xs"]{ - font-size: 8px; -} - -QLabel[style="text-sm"]{ - font-size: 10px; -} - -QLabel[style="text-md"] { - font-size: 12px; -} - -QLabel[style="text-xl"] { - font-size: 14px; -} - -QFrame[style="QConditionsWidget"] { - margin: 0px; - border: 0px; - padding: 0px; - background: transparent; -} - -QGroupBox[style="QWeatherWidget"] { - padding: 0px; - margin-left: 0px; - margin-right: 5px; - margin-top: 1px; - margin-bottom: 5px; -} - -QGroupBox[style="QWeatherWidget"] QLabel[style="text-sm"] { - padding: 0px; - margin: 0px; - font-size: 9px; - line-height: 9px; -} - -QGroupBox[style="IntelSummary"] { - padding-left: 40px; - padding-right: 0px; - padding-top: 0px; - padding-bottom: 0px; - margin-left: 0px; - margin-right: 5px; - margin-top: 1px; - margin-bottom: 5px; -} - -QGroupBox[style="IntelSummary"] QLabel { - padding: 0px; - margin: 0px; - font-size: 9px; - line-height: 9px; - color: #fff; - background: transparent; -} - -QCalendarWidget -{ - background-color:#ff0000; - border: 1px solid black; -} - -QCalendarWidget QAbstractItemView -{ - background-color:#699245; - border: 1px solid black; -} - -QCalendarWidget QWidget { - color: #B7C0C6; -} - -QCalendarWidget QTableView{ - border-width: 2px; - background-color:lightgrey; - border: 1px solid black; -} \ No newline at end of file diff --git a/resources/stylesheets/style.css b/resources/stylesheets/style.css deleted file mode 100644 index 792593673..000000000 --- a/resources/stylesheets/style.css +++ /dev/null @@ -1,205 +0,0 @@ - - -/*QWidget { - background-color: #4E5760; - color:white; -} - -QComboxBox { - background-color: #fff; - color:white; -} - -QLiberationWindow{ - background-color: #4E5760; - color:white; -} - -QTopPanel, -QTopPanel *{ - background-color: #aaa; - color: white; - font-size: 12px; - font-weight: bold; -}*/ - -QPushButton[style="btn-success"]{ - background-color:#699245; - color: white; - padding: 5px 5px 5px 5px; - border-radius:5px; -} - -QPushButton[style="btn-success"]:hover{ - background-color:#8ABC5A; - padding: 5px 5px 5px 5px; - border-radius:5px; -} - -QPushButton[style="start-button"]{ - background-color:#699245; - color: white; - padding: 5px 5px 5px 5px; - border-radius:5px; -} - -QPushButton[style="start-button"]:hover{ - background-color:#8ABC5A; - padding: 15px 15px 15px 15px; - border-radius:5px; -} - -/* Buy button */ -QPushButton[style="btn-buy"]{ - background-color:#82A466; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; - margin: 0px; - padding: 2px; -} - -QPushButton[style="btn-buy"]:hover{ - background:#5C863F; -} - -/* Sell button */ -QPushButton[style="btn-sell"]{ - background-color:#9E3232; - color: white; - border-radius:2px; - font-weight:bold; - text-transform:uppercase; - margin: 0px; - padding: 2px; -} - -QPushButton[style="btn-sell"]:hover{ - background:#D84545; -} - -QPushButton[style="btn-danger"]{ - background-color:#9E3232; - color: white; - padding: 5px 5px 5px 5px; - border-radius:5px; -} - -QPushButton[style="btn-danger"]:hover{ - background-color:#D84545; - padding: 5px 5px 5px 5px; - border-radius:5px; -} - -QLabel[style="base-title"]{ - font-size: 24px; - border: 1px solid #ccc; -} - -QLabel[style="icon-plane"]{ - background-color:#48719D; - min-height:24px; - max-width: 84px; - border: 1px solid black; - text-align:center; - color:white; -} - -QLabel[style="icon-armor"]{ - background-color:#48719D; - min-height:24px; - max-width: 64px; - border: 1px solid black; - text-align:center; - color:white; -} - -QLabel[style="bordered"]{ - border: 1px solid black; -} - -QLabel[style="BARCAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; -} - -QLabel[style="TARCAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; -} - -QLabel[style="CAP"]{ - border: 1px solid black; - background-color: #445299; - color:white; -} - -QLabel[style="INTERCEPTION"]{ - border: 1px solid black; - background-color: #7752bc; - color:white; -} - -QLabel[style="CAS"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; -} - -QLabel[style="BAI"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; -} - -QLabel[style="ANTISHIP"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; -} - -QLabel[style="STRIKE"]{ - border: 1px solid black; - background-color: #ab2244; - color:white; -} - -QLabel[style="DEAD"]{ - border: 1px solid black; - background-color: #cc8844; - color:white; -} - -QLabel[style="SEAD"]{ - border: 1px solid black; - background-color: #aa7744; - color:white; -} - -/*QBaseMenu{ - background-color:#699245; - color:white; -} - -QWidget[style="baseMenuHeader"]{ - font-size: 24px; - font-weight: bold; -}*/ - -QLabel[style="small"]{ - font-size: 8px; -} - -QCheckBox:disabled { - color: #888888; -} -QCheckBox::indicator:disabled { - background-color: rgba(255, 255, 255, 5%); -} - -QLabel:disabled { - color: #888888; -} \ No newline at end of file diff --git a/resources/stylesheets/windows-style.css b/resources/stylesheets/windows-style.css deleted file mode 100644 index 5d6c99eae..000000000 --- a/resources/stylesheets/windows-style.css +++ /dev/null @@ -1,11 +0,0 @@ -/* -windows basis styles -*/ - -/* - * Makes all message box text selectable. - * https://stackoverflow.com/a/32595502/632035 - */ -QMessageBox { - messagebox-text-interaction-flags: 5; -} \ No newline at end of file diff --git a/resources/syria.gif b/resources/syria.gif deleted file mode 100644 index 24a39c944..000000000 Binary files a/resources/syria.gif and /dev/null differ diff --git a/resources/theaters/caucasus/info.yaml b/resources/theaters/caucasus/info.yaml deleted file mode 100644 index aac343701..000000000 --- a/resources/theaters/caucasus/info.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Caucasus -timezone: +4 -daytime: - dawn: [6, 9] - day: [9, 18] - dusk: [18, 20] - night: [0, 5] -climate: - day_night_temperature_difference: 6.0 - seasons: - winter: - average_pressure: 29.72 # TODO: Find real-world data - average_temperature: 3.0 - weather: - thunderstorm: 1 - raining: 20 - cloudy: 60 - clear: 20 - spring: - weather: - thunderstorm: 1 - raining: 20 - cloudy: 40 - clear: 40 - summer: - average_pressure: 30.02 # TODO: Find real-world data - average_temperature: 22.5 - weather: - thunderstorm: 1 - raining: 10 - cloudy: 35 - clear: 55 - fall: - weather: - thunderstorm: 1 - raining: 30 - cloudy: 50 - clear: 20 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/caucasus/landmap.p b/resources/theaters/caucasus/landmap.p deleted file mode 100644 index 5b053f1de..000000000 Binary files a/resources/theaters/caucasus/landmap.p and /dev/null differ diff --git a/resources/theaters/falklands/info.yaml b/resources/theaters/falklands/info.yaml deleted file mode 100644 index 3f9e42c08..000000000 --- a/resources/theaters/falklands/info.yaml +++ /dev/null @@ -1,53 +0,0 @@ ---- -name: Falklands -timezone: -3 -daytime: - dawn: [6, 9] - day: [9, 18] - dusk: [18, 20] - night: [0, 5] -# Sourced from -# https://www.worlddata.info/america/argentina/climate-santa-cruz.php -# This map is huge and probably has wide climate variations across the region, -# but that's not something we (or DCS) can model, so Santa Cruz was picked -# arbitrarily. -# Pressure data sourced from -# https://www.weather-atlas.com/en/argentina/puerto-santa-cruz-climate#pressure -climate: - day_night_temperature_difference: 11.0 - seasons: - # "winter" and "summer" are actually interpreted as northern hemisphere - # seasons in liberation, so these seasons are all inverted. - winter: - average_pressure: 29.63 - average_temperature: 21.0 - weather: - thunderstorm: 1 - raining: 10 - cloudy: 55 - clear: 35 - spring: - weather: - thunderstorm: 1 - raining: 10 - cloudy: 65 - clear: 25 - summer: - average_pressure: 29.77 - average_temperature: -2.0 - weather: - thunderstorm: 1 - raining: 5 - cloudy: 75 - clear: 20 - fall: - weather: - thunderstorm: 1 - raining: 30 - cloudy: 45 - clear: 25 - turbulence: - high_avg_yearly_turbulence_per_10cm: 8 - low_avg_yearly_turbulence_per_10cm: 4.5 - solar_noon_turbulence_per_10cm: 3 - midnight_turbulence_per_10cm: -2 \ No newline at end of file diff --git a/resources/theaters/falklands/landmap.p b/resources/theaters/falklands/landmap.p deleted file mode 100644 index 4b669371a..000000000 Binary files a/resources/theaters/falklands/landmap.p and /dev/null differ diff --git a/resources/theaters/marianaislands/info.yaml b/resources/theaters/marianaislands/info.yaml deleted file mode 100644 index e8a0bcf8b..000000000 --- a/resources/theaters/marianaislands/info.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: Mariana Islands -pydcs_name: MarianaIslands -timezone: +10 -daytime: - dawn: [6, 8] - day: [8, 16] - dusk: [16, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 6.0 - seasons: - winter: - average_pressure: 29.82 # TODO: Find real-world data - average_temperature: 27.0 - weather: - thunderstorm: 2 - raining: 20 - cloudy: 40 - clear: 40 - spring: - weather: - thunderstorm: 1 - raining: 10 - cloudy: 30 - clear: 60 - summer: - average_pressure: 30.02 # TODO: Find real-world data - average_temperature: 28.0 - weather: - thunderstorm: 2 - raining: 20 - cloudy: 40 - clear: 40 - fall: - weather: - thunderstorm: 5 - raining: 45 - cloudy: 30 - clear: 20 - turbulence: - high_avg_yearly_turbulence_per_10cm: 6.5 - low_avg_yearly_turbulence_per_10cm: 4.5 - solar_noon_turbulence_per_10cm: 2 - midnight_turbulence_per_10cm: -1 \ No newline at end of file diff --git a/resources/theaters/marianaislands/landmap.p b/resources/theaters/marianaislands/landmap.p deleted file mode 100644 index d11e03684..000000000 Binary files a/resources/theaters/marianaislands/landmap.p and /dev/null differ diff --git a/resources/theaters/nevada/info.yaml b/resources/theaters/nevada/info.yaml deleted file mode 100644 index d98f1064d..000000000 --- a/resources/theaters/nevada/info.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Nevada -timezone: -8 -daytime: - dawn: [4, 6] - day: [6, 17] - dusk: [17, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 6.0 - seasons: - winter: - average_pressure: 29.72 # TODO: Find real-world data - average_temperature: 5.0 - weather: - thunderstorm: 1 - raining: 10 - cloudy: 50 - clear: 40 - spring: - weather: - thunderstorm: 1 - raining: 5 - cloudy: 45 - clear: 50 - summer: - average_pressure: 30.02 # TODO: Find real-world data - average_temperature: 31.5 - weather: - thunderstorm: 1 - raining: 5 - cloudy: 30 - clear: 65 - fall: - weather: - thunderstorm: 1 - raining: 10 - cloudy: 45 - clear: 45 - turbulence: - high_avg_yearly_turbulence_per_10cm: 17 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/nevada/landmap.p b/resources/theaters/nevada/landmap.p deleted file mode 100644 index f8ef5cbbf..000000000 Binary files a/resources/theaters/nevada/landmap.p and /dev/null differ diff --git a/resources/theaters/normandy/info.yaml b/resources/theaters/normandy/info.yaml deleted file mode 100644 index 320c6f089..000000000 --- a/resources/theaters/normandy/info.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Normandy -timezone: +0 -daytime: - dawn: [6, 8] - day: [10, 17] - dusk: [17, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 5.0 - seasons: - winter: - average_pressure: 29.72 # TODO: Find real-world data - average_temperature: 0.0 - weather: - thunderstorm: 1 - raining: 20 - cloudy: 60 - clear: 20 - spring: - weather: - thunderstorm: 1 - raining: 20 - cloudy: 40 - clear: 40 - summer: - average_pressure: 30.02 # TODO: Find real-world data - average_temperature: 20.0 - weather: - thunderstorm: 1 - raining: 10 - cloudy: 35 - clear: 55 - fall: - weather: - thunderstorm: 1 - raining: 30 - cloudy: 50 - clear: 20 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/normandy/landmap.p b/resources/theaters/normandy/landmap.p deleted file mode 100644 index 6dea5a44c..000000000 Binary files a/resources/theaters/normandy/landmap.p and /dev/null differ diff --git a/resources/theaters/persian gulf/info.yaml b/resources/theaters/persian gulf/info.yaml deleted file mode 100644 index c4529c39e..000000000 --- a/resources/theaters/persian gulf/info.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: Persian Gulf -pydcs_name: PersianGulf -timezone: +4 -daytime: - dawn: [6, 8] - day: [8, 16] - dusk: [16, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 2.0 - seasons: - winter: - average_pressure: 29.80 # TODO: Find real-world data - average_temperature: 15.0 - weather: - thunderstorm: 1 - raining: 15 - cloudy: 40 - clear: 45 - spring: - weather: - thunderstorm: 1 - raining: 2 - cloudy: 28 - clear: 70 - summer: - average_pressure: 29.98 # TODO: Find real-world data - average_temperature: 32.5 - weather: - thunderstorm: 1 - raining: 1 - cloudy: 18 - clear: 80 - fall: - weather: - thunderstorm: 1 - raining: 2 - cloudy: 28 - clear: 70 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 4.5 - solar_noon_turbulence_per_10cm: 5.5 - midnight_turbulence_per_10cm: -2 \ No newline at end of file diff --git a/resources/theaters/persian gulf/landmap.p b/resources/theaters/persian gulf/landmap.p deleted file mode 100644 index 98fe5bce7..000000000 Binary files a/resources/theaters/persian gulf/landmap.p and /dev/null differ diff --git a/resources/theaters/sinai/info.yaml b/resources/theaters/sinai/info.yaml deleted file mode 100644 index a378c6642..000000000 --- a/resources/theaters/sinai/info.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Sinai -timezone: +2 -daytime: - dawn: [6, 8] - day: [8, 16] - dusk: [16, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 8.0 - seasons: - winter: - average_pressure: 29.86 # TODO: Find real-world data - average_temperature: 10.0 - weather: - thunderstorm: 1 - raining: 25 - cloudy: 35 - clear: 40 - spring: - weather: - thunderstorm: 1 - raining: 10 - cloudy: 30 - clear: 60 - summer: - average_pressure: 29.98 # TODO: Find real-world data - average_temperature: 28.5 - weather: - thunderstorm: 1 - raining: 5 - cloudy: 30 - clear: 65 - fall: - weather: - thunderstorm: 1 - raining: 15 - cloudy: 35 - clear: 50 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 diff --git a/resources/theaters/sinai/landmap.p b/resources/theaters/sinai/landmap.p deleted file mode 100644 index 67d68355e..000000000 Binary files a/resources/theaters/sinai/landmap.p and /dev/null differ diff --git a/resources/theaters/syria/info.yaml b/resources/theaters/syria/info.yaml deleted file mode 100644 index cb763e899..000000000 --- a/resources/theaters/syria/info.yaml +++ /dev/null @@ -1,44 +0,0 @@ ---- -name: Syria -timezone: +3 -daytime: - dawn: [6, 8] - day: [8, 16] - dusk: [16, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 8.0 - seasons: - winter: - average_pressure: 29.86 # TODO: Find real-world data - average_temperature: 10.0 - weather: - thunderstorm: 1 - raining: 25 - cloudy: 35 - clear: 40 - spring: - weather: - thunderstorm: 1 - raining: 10 - cloudy: 30 - clear: 60 - summer: - average_pressure: 29.98 # TODO: Find real-world data - average_temperature: 28.5 - weather: - thunderstorm: 1 - raining: 5 - cloudy: 30 - clear: 65 - fall: - weather: - thunderstorm: 1 - raining: 15 - cloudy: 35 - clear: 50 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/syria/landmap.p b/resources/theaters/syria/landmap.p deleted file mode 100644 index 1a2a5fa4d..000000000 Binary files a/resources/theaters/syria/landmap.p and /dev/null differ diff --git a/resources/theaters/the channel/info.yaml b/resources/theaters/the channel/info.yaml deleted file mode 100644 index b10e34f59..000000000 --- a/resources/theaters/the channel/info.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -name: The Channel -pydcs_name: TheChannel -timezone: +2 -daytime: - dawn: [6, 8] - day: [10, 17] - dusk: [17, 18] - night: [0, 5] -climate: - day_night_temperature_difference: 5.0 - seasons: - winter: - average_pressure: 29.72 # TODO: Find real-world data - average_temperature: 0.0 - weather: - thunderstorm: 1 - raining: 20 - cloudy: 60 - clear: 20 - spring: - weather: - thunderstorm: 1 - raining: 20 - cloudy: 40 - clear: 40 - summer: - average_pressure: 30.02 # TODO: Find real-world data - average_temperature: 20.0 - weather: - thunderstorm: 1 - raining: 10 - cloudy: 35 - clear: 55 - fall: - weather: - thunderstorm: 1 - raining: 30 - cloudy: 50 - clear: 20 - turbulence: - high_avg_yearly_turbulence_per_10cm: 9 - low_avg_yearly_turbulence_per_10cm: 3.5 - solar_noon_turbulence_per_10cm: 3.5 - midnight_turbulence_per_10cm: -3 \ No newline at end of file diff --git a/resources/theaters/the channel/landmap.p b/resources/theaters/the channel/landmap.p deleted file mode 100644 index 92864e8cb..000000000 Binary files a/resources/theaters/the channel/landmap.p and /dev/null differ diff --git a/resources/tools/arcgis_landmap_import.py b/resources/tools/arcgis_landmap_import.py deleted file mode 100644 index d4b20af46..000000000 --- a/resources/tools/arcgis_landmap_import.py +++ /dev/null @@ -1,223 +0,0 @@ -"""Generates landmaps from GIS shapefiles.""" -import argparse -import logging -import pickle -from collections.abc import Iterator -from enum import Enum, unique -from pathlib import Path - -from pyproj import CRS, Transformer -from shapefile import Reader, Shape -from shapely import validation -from shapely.geometry import LineString, MultiPolygon, Polygon, shape -from shapely.ops import unary_union - -from game.profiling import logged_duration -from game.theater import ConflictTheater, Landmap -from game.theater.theaterloader import TheaterLoader -from resources.tools.generate_landmap import to_multipoly - -THIS_DIR = Path(__file__).resolve() -TOP_DIR = THIS_DIR.parents[2] -IMPORT_DIR = TOP_DIR / "unshipped_data/arcgis_maps" -RESOURCES_DIR = TOP_DIR / "resources" - - -ALL_THEATER_NAMES = [d.name for d in (RESOURCES_DIR / "theaters").iterdir()] - - -@unique -class ShapeType(Enum): - LAND = "land" - SEA = "sea" - EXCLUSION = "exclusion" - - @property - def import_directory_name(self) -> str: - return self.value - - -class CoordinateConverter: - def __init__(self, theater: ConflictTheater, projection_file: Path) -> None: - self.theater = theater - self.transformer = self._transformer_for(projection_file) - - def convert_to_dcs_coords(self, polys: list[Polygon]) -> list[Polygon]: - new_polys = [] - for poly in polys: - for boundary, holes in self._boundary_and_holes_of(poly): - new_polys.append( - validation.make_valid( - Polygon( - self._convert_line_to_dcs_coords(boundary), - holes=[ - self._convert_line_to_dcs_coords(hole) for hole in holes - ], - ) - ) - ) - return new_polys - - def _transformer_for(self, projection_file: Path) -> Transformer: - prj = projection_file.read_text() - return Transformer.from_crs( - CRS(prj), self.theater.terrain.projection_parameters.to_crs() - ) - - @staticmethod - def _boundary_and_holes_of(poly: Polygon) -> Iterator[LineString, list[LineString]]: - try: - boundary, *holes = poly.boundary.geoms - yield boundary, holes - except AttributeError: - yield poly.boundary, [] - - def _convert_line_to_dcs_coords( - self, line: LineString - ) -> list[tuple[float, float]]: - return [self.transformer.transform(x, y) for x, y in line.coords] - - -class ShapefileReader: - def __init__( - self, theater_name: str, theater: ConflictTheater, shape_type: ShapeType - ) -> None: - self.theater_name = theater_name - self.theater = theater - self.shape_type = shape_type - - def read_dcs_polys(self) -> list[Polygon]: - shapefile = self._shapefile_path - logging.debug( - f"Reading ARCGIS landmap {self.shape_type.value} data from {shapefile}" - ) - with logged_duration("Loading polygons"): - raw_polys = self._load_raw_polys_from_shapefile(shapefile) - logging.debug("Converting to DCS coordinate system") - with logged_duration("Converting shapefile data to DCS coordinates"): - converter = CoordinateConverter(self.theater, shapefile.with_suffix(".prj")) - return converter.convert_to_dcs_coords(raw_polys) - - @staticmethod - def _polys_from_map_shape(map_shape: Shape) -> list[Polygon]: - geoms = shape(map_shape) - try: - return geoms.geoms - except AttributeError: - return [geoms] - - def _load_raw_polys_from_shapefile(self, shapefile: Path) -> list[Polygon]: - polys: list[Polygon] = [] - with Reader(shapefile) as reader: - shapes = reader.shapes() - for idx, map_shape in enumerate(shapes): - polys.extend(self._polys_from_map_shape(map_shape)) - return polys - - @property - def _import_directory(self) -> Path: - return IMPORT_DIR / self.theater_name / self.shape_type.import_directory_name - - @property - def _shapefile_path(self) -> Path: - import_dir = self._import_directory - files = list(import_dir.glob("*.shp")) - if len(files) != 1: - raise RuntimeError( - f"Could not find a unique file matching {import_dir / '*.shp'}" - ) - return files[0] - - -class PolygonFilter: - def __init__(self, min_size_sq_m: float) -> None: - self.min_size_sq_m = min_size_sq_m - - def filter(self, polys: list[Polygon]) -> list[Polygon]: - logging.debug("Filtering small polys") - with logged_duration("Filtering small polys"): - return self._ignore_small_polys(polys) - - def _ignore_small_polys(self, polys: list[Polygon]) -> list[Polygon]: - # Polygons are in DCS coordinates, which are in meters. - filtered = [p for p in polys if p.area >= self.min_size_sq_m] - logging.debug( - "Filtered %d polygons smaller than %d sq meters", - len(polys) - len(filtered), - self.min_size_sq_m, - ) - return filtered - - -class Importer: - def __init__(self, theater_name: str) -> None: - self.theater_name = theater_name - self.theater = TheaterLoader(theater_name).load() - - def generate_landmap(self) -> Landmap: - return Landmap( - inclusion_zones=self._terrain_multipoly_for(ShapeType.LAND), - exclusion_zones=self._terrain_multipoly_for(ShapeType.EXCLUSION), - sea_zones=self._terrain_multipoly_for(ShapeType.SEA), - ) - - def _terrain_multipoly_for(self, shape_type: ShapeType) -> MultiPolygon: - polys = ShapefileReader( - self.theater_name, self.theater, shape_type - ).read_dcs_polys() - polys = PolygonFilter(min_size_sq_m=50**2).filter(polys) - logging.debug("Merging %d polys", len(polys)) - with logged_duration("Merging polygons"): - # Multithreading on our side will not speed up unary_union. This was - # benchmarked during development with a chunked merge, but all chunk sizes - # tested underperformed the single call. Testing with the Falklands - # exclusion polys (do not compare these numbers to your local results, the - # input data has likely changed). - # - # Chunk size of 10: 4m30s - # Chunk size of 100: 3m55s - # Chunk size of 1000: 3m50s - # No chunking: 3m35s - # - # The most expensive part of the process was always the final merge. This is - # probably because there are too many disconnected polygons, so the earlier - # merges did not actually combine many polys, but instead just (slowly) - # created multipolygons. - return to_multipoly(unary_union(polys)) - - -def write_landmap(theater_name: str, landmap: Landmap) -> None: - with TheaterLoader(theater_name).landmap_path.open("wb") as landmap_file: - pickle.dump(landmap, landmap_file) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser() - - parser.add_argument( - "theater", - choices=ALL_THEATER_NAMES, - help="Name of the theater to import.", - ) - - return parser.parse_args() - - -def main() -> None: - logging.basicConfig(level=logging.DEBUG) - - args = parse_args() - - with logged_duration("Shapefile import and landmap generation"): - landmap = Importer(args.theater).generate_landmap() - write_landmap(args.theater, landmap) - logging.info( - "Final landmap has %d land, %d sea, and %d exclusion polys", - len(landmap.inclusion_zones.geoms), - len(landmap.sea_zones.geoms), - len(landmap.exclusion_zones.geoms), - ) - - -if __name__ == "__main__": - main() diff --git a/resources/tools/cau_groundobjects.miz b/resources/tools/cau_groundobjects.miz deleted file mode 100644 index 507aa7e7f..000000000 Binary files a/resources/tools/cau_groundobjects.miz and /dev/null differ diff --git a/resources/tools/cau_terrain.miz b/resources/tools/cau_terrain.miz deleted file mode 100644 index a0a53f08f..000000000 Binary files a/resources/tools/cau_terrain.miz and /dev/null differ diff --git a/resources/tools/channel_terrain.miz b/resources/tools/channel_terrain.miz deleted file mode 100644 index a968dadec..000000000 Binary files a/resources/tools/channel_terrain.miz and /dev/null differ diff --git a/resources/tools/datalint.py b/resources/tools/datalint.py deleted file mode 100644 index a3a815a90..000000000 --- a/resources/tools/datalint.py +++ /dev/null @@ -1,174 +0,0 @@ -from __future__ import annotations - -import argparse -import contextlib -import logging -import subprocess -import sys -import textwrap -from abc import ABC, abstractmethod -from collections.abc import Iterable, Iterator -from datetime import date -from pathlib import Path -from typing import TextIO, TypeAlias - -from game import VERSION - - -class ReportElement(ABC): - @abstractmethod - def __str__(self) -> str: - ... - - -class Heading(ReportElement): - def __init__(self, level: int, text: str) -> None: - self.level = level - self.text = text - - def __str__(self) -> str: - return f"{'#' * self.level} {self.text}" - - -class H1(Heading): - def __init__(self, text: str) -> None: - super().__init__(1, text) - - -class H2(Heading): - def __init__(self, text: str) -> None: - super().__init__(2, text) - - -class H3(Heading): - def __init__(self, text: str) -> None: - super().__init__(3, text) - - -class Paragraph(ReportElement): - def __init__(self, text: str) -> None: - self.text = text - - def __str__(self) -> str: - return textwrap.fill(self.text, width=80) - - -class UnorderedList(ReportElement): - def __init__(self, items: Iterable[str]) -> None: - self.items = list(items) - if not self.items: - raise ValueError("List has no data") - - def __str__(self) -> str: - return "\n".join(f"* {item}" for item in self.items) - - -class Reporter: - def __init__(self, output: TextIO) -> None: - self.output = output - - def write(self, element: ReportElement) -> None: - print(f"{element}\n", file=self.output) - - -ReportStream: TypeAlias = Iterator[ReportElement] - - -class LinterBase(ABC): - def stream_reports(self) -> ReportStream: - ... - - -class UncheckedDataLinter(LinterBase): - def stream_reports(self) -> ReportStream: - yield H2("Unchecked data") - yield Paragraph("Any types of data not mentioned above are **not checked**.") - - -class Linter(LinterBase): - def __init__(self, output: TextIO) -> None: - self.reporter = Reporter(output) - - def run(self) -> None: - for report in self.stream_reports(): - self.reporter.write(report) - - def stream_reports(self) -> ReportStream: - yield H1("Liberation data report") - yield self.describe_version() - yield Paragraph( - "This report documents missing supplemental data in Liberation. This is " - "only able to report data that is missing as compared to pydcs. If pydcs " - "is missing DCS data, that cannot be reported." - ) - yield Paragraph( - "**Accuracy of data cannot be verified by this report.** If data not " - "mentioned in this report is present but **wrong**, file a bug." - ) - yield from UncheckedDataLinter().stream_reports() - - def describe_version(self) -> ReportElement: - sha = subprocess.run( - ["git", "rev-parse", "--short", "HEAD"], - check=True, - capture_output=True, - text=True, - ).stdout.strip() - return Paragraph( - f"This report was generated for DCS Liberation {VERSION} ({sha}) on " - f"{date.today()} with pydcs {self.describe_pydcs()}." - ) - - def describe_pydcs(self) -> str: - result = subprocess.run( - ["pip", "freeze"], check=True, capture_output=True, text=True - ) - pydcs_lines = [l for l in result.stdout.splitlines() if "pydcs" in l] - if len(pydcs_lines) != 1: - raise RuntimeError( - "Could not find unique pydcs package in `pip freeze` output:\n" - f"{result.stdout}" - ) - version = pydcs_lines[0] - if version.startswith("-e git+"): - return self.format_pip_git(version) - return version - - @staticmethod - def format_pip_git(version: str) -> str: - _, _, version = version.partition("+") - if version.endswith("#egg=pydcs"): - version, _, _ = version.rpartition("#") - _, _, sha = version.partition("@") - return sha - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser() - - parser.add_argument( - "output_path", - type=Path, - nargs="?", - help=( - "Write the report to the given path. If omitted, the report will be " - "written to stdout." - ), - ) - - return parser.parse_args() - - -def main() -> None: - logging.basicConfig(level=logging.DEBUG) - args = parse_args() - if args.output_path is None: - context = contextlib.nullcontext(sys.stdout) - else: - context = args.output_path.open("w") - with context as output: - Linter(output).run() - - -if __name__ == "__main__": - main() diff --git a/resources/tools/dcs b/resources/tools/dcs deleted file mode 120000 index 49fd884be..000000000 --- a/resources/tools/dcs +++ /dev/null @@ -1 +0,0 @@ -../../submodules/dcs/dcs \ No newline at end of file diff --git a/resources/tools/fix_layout_orientation.py b/resources/tools/fix_layout_orientation.py deleted file mode 100644 index f462fbecb..000000000 --- a/resources/tools/fix_layout_orientation.py +++ /dev/null @@ -1,63 +0,0 @@ -# Script to update a layout.miz which is not created with an orientation of Heading=0 -# It loads the miz as and reorientates all objects - - -# Requirement: Only ONE Group has to be within the miz file. -# Load miz -# Determine Center and current heading (use first unit for that) -# Rotate everything around the center with the difference to heading 0 -# Save the miz - -import argparse -import itertools -from typing import Any - -import dcs - -from game.point_with_heading import PointWithHeading -from game.utils import Heading - - -def fix_orientation(miz_file: str) -> None: - mission = dcs.Mission() - mission.load_file(miz_file) - groups = [] - # Load all units from the miz - for country in itertools.chain( - mission.coalition["red"].countries.values(), - mission.coalition["blue"].countries.values(), - ): - for dcs_group in itertools.chain( - mission.country(country.name).vehicle_group, - mission.country(country.name).ship_group, - mission.country(country.name).static_group, - ): - groups.append(dcs_group) - - # Get the center which will be used as origin for the rotation - center_unit = groups[0].units[0] - - # Calculate the rotation - rotation = Heading.from_degrees(360 - int(center_unit.heading)) - - # Rotate all units - for group in groups: - for unit in group.units: - unit.position = PointWithHeading.from_point( - unit.position, Heading.from_degrees(int(unit.heading)) + rotation - ) - unit.heading = unit.position.heading.degrees - unit.position.rotate(center_unit.position, rotation) - group.points[0].position = group.units[0].position - # Save the miz - mission.save() - - -def main() -> None: - parser = argparse.ArgumentParser() - parser.add_argument("mission", type=str, help="The mission which will be fixed") - args = parser.parse_args() - fix_orientation(args.mission) - - -main() diff --git a/resources/tools/generate_frontlines.py b/resources/tools/generate_frontlines.py deleted file mode 100644 index ced861c65..000000000 --- a/resources/tools/generate_frontlines.py +++ /dev/null @@ -1,88 +0,0 @@ -from __future__ import annotations - -import json -import argparse -from pathlib import Path -from typing import List, Tuple, Union, Dict - -from dcs.terrain import ( - Caucasus, - PersianGulf, - Syria, - Nevada, - Normandy, - TheChannel, - MarianaIslands, -) -from dcs import Mission - -Terrain = Union[ - Caucasus, PersianGulf, Syria, Nevada, Normandy, TheChannel, MarianaIslands -] - -SAVE_PATH = Path("resources/frontlines") - - -def validate_miz(file_path: Path) -> bool: - return bool(file_path.suffix == ".miz" and file_path.exists()) - - -def validate_airports(airports: Tuple[int], terrain: Terrain): - for airport in airports: - if terrain.airport_by_id(airport) is None: - print(f"Cannot load airport for invalid id {airport}") - - -def load_files(files) -> List[Mission]: - missions = [] - for file in files: - if validate_miz(file): - mission = Mission() - mission.load_file(file) - missions.append(mission) - else: - print(f"Error: {file} doesn't look like a valid mission file.") - return missions - - -def create_frontline_dict(mission: Mission) -> Dict[str, Dict]: - frontline_dict = {} - for group in mission.country("USA").vehicle_group: - groupname = str(group.name).replace(group.name.id, "").replace(":", "") - control_points = groupname.split("|") - frontline_dict[groupname] = { - "points": [(i.position.x, i.position.y) for i in group.points], - "start_cp": int(control_points[0]), - } - return frontline_dict - - -def process_missions(missions: List[Mission]) -> None: - for mission in missions: - frontline_dict = create_frontline_dict(mission) - write_json(frontline_dict, mission.terrain.name.lower()) - - -def write_json(frontline_dict: Dict[str, Dict], terrain_name: str) -> None: - with open(SAVE_PATH.joinpath(terrain_name + ".json"), "w") as file: - json.dump(frontline_dict, file) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser( - description="Process a miz file to create json descriptions of multi-segment frontlines" - ) - parser.add_argument( - "files", - metavar="N", - type=Path, - nargs="+", - help="A list of space separated .miz files to extract frontlines from", - ) - - args = parser.parse_args() - missions = load_files(args.files) - process_missions(missions) - # frontline_dict = create_frontline_dict(missions[0]) - - print("Done") diff --git a/resources/tools/generate_landmap.py b/resources/tools/generate_landmap.py deleted file mode 100644 index 6fb52796a..000000000 --- a/resources/tools/generate_landmap.py +++ /dev/null @@ -1,84 +0,0 @@ -import pickle -from functools import singledispatch - -from dcs.mission import Mission -from shapely.geometry import GeometryCollection, MultiPolygon, Polygon -from shapely.ops import unary_union - -from game.theater.landmap import Landmap - - -@singledispatch -def to_multipoly(obj) -> MultiPolygon: - raise NotImplementedError( - f"to_multipoly not implemented for {obj.__class__.__name__}" - ) - - -@to_multipoly.register -def _poly_to_multipoly(obj: Polygon) -> MultiPolygon: - return MultiPolygon([obj]) - - -@to_multipoly.register -def _multipoly_to_multipoly(obj: MultiPolygon) -> MultiPolygon: - return obj - - -@to_multipoly.register -def _geometry_collection_to_multipoly(obj: GeometryCollection) -> MultiPolygon: - if obj.is_empty: - return MultiPolygon() - raise RuntimeError(f"Not sure how to convert collection to multipoly: {obj.wkt}") - - -def main() -> None: - for terrain in [ - "cau", - "nev", - "syria", - "channel", - "normandy", - "gulf", - "marianaislands", - ]: - print("Terrain " + terrain) - m = Mission() - m.load_file("./{}_terrain.miz".format(terrain)) - - inclusion_zones = [] - exclusion_zones = [] - seas_zones = [] - for plane_group in m.country("USA").plane_group: - zone = [(x.position.x, x.position.y) for x in plane_group.points] - - if terrain == "cau" and inclusion_zones: - # legacy - exclusion_zones.append(Polygon(zone)) - else: - poly = Polygon(zone) - if not poly.is_valid: - raise RuntimeError(f"{plane_group} is invalid") - if plane_group.units[0].type == "F-15C": - exclusion_zones.append(poly) - else: - inclusion_zones.append(poly) - - for ship_group in m.country("USA").ship_group: - zone = [(x.position.x, x.position.y) for x in ship_group.points] - seas_zones.append(Polygon(zone)) - - with open("../{}landmap.p".format(terrain), "wb") as f: - print(len(inclusion_zones), len(exclusion_zones), len(seas_zones)) - pickle.dump( - Landmap( - to_multipoly(unary_union(inclusion_zones)), - to_multipoly(unary_union(exclusion_zones)), - to_multipoly(unary_union(seas_zones)), - ), - f, - ) - - -if __name__ == "__main__": - main() diff --git a/resources/tools/groundobject_templates.miz b/resources/tools/groundobject_templates.miz deleted file mode 100644 index da8d133c6..000000000 Binary files a/resources/tools/groundobject_templates.miz and /dev/null differ diff --git a/resources/tools/gulf_terrain.miz b/resources/tools/gulf_terrain.miz deleted file mode 100644 index 36cbb941c..000000000 Binary files a/resources/tools/gulf_terrain.miz and /dev/null differ diff --git a/resources/tools/import_beacons.py b/resources/tools/import_beacons.py deleted file mode 100644 index 026b9c99b..000000000 --- a/resources/tools/import_beacons.py +++ /dev/null @@ -1,208 +0,0 @@ -"""Generates resources/dcs/beacons.json from the DCS installation. - -DCS has a beacons.lua file for each terrain mod that includes information about -the radio beacons present on the map: - -beacons = { - { - display_name = _('INCIRLIC'); - beaconId = 'airfield16_0'; - type = BEACON_TYPE_VORTAC; - callsign = 'DAN'; - frequency = 108400000.000000; - channel = 21; - position = { 222639.437500, 73.699811, -33216.257813 }; - direction = 0.000000; - positionGeo = { latitude = 37.015611, longitude = 35.448194 }; - sceneObjects = {'t:124814096'}; - }; - ... -} - -""" -import argparse -import dataclasses -import gettext -import json -import logging -import os -import textwrap -from contextlib import contextmanager -from pathlib import Path -from typing import Dict, Iterable, Union - -import lupa - -from game.dcs.beacons import BEACONS_RESOURCE_PATH, Beacon, BeaconType - -THIS_DIR = Path(__file__).parent.resolve() -SRC_DIR = THIS_DIR.parents[1] -EXPORT_DIR = SRC_DIR / BEACONS_RESOURCE_PATH - - -@contextmanager -def cd(path: Path): - cwd = os.getcwd() - os.chdir(path) - try: - yield - finally: - os.chdir(cwd) - - -def convert_lua_frequency(raw: Union[float, int]) -> int: - if isinstance(raw, float): - if not raw.is_integer(): - # The values are in hertz, and everything should be a whole number. - raise ValueError(f"Unexpected non-integer frequency: {raw}") - return int(raw) - else: - return raw - - -def beacons_from_terrain(dcs_path: Path, path: Path) -> Iterable[tuple[str, Beacon]]: - logging.info(f"Loading terrain data from {path}") - # TODO: Fix case-sensitive issues. - # The beacons.lua file differs by case in some terrains. Will need to be - # fixed if the tool is to be run on Linux, but presumably the server - # wouldn't be able to find these anyway. - beacons_lua = path / "beacons.lua" - with cd(dcs_path): - lua = lupa.LuaRuntime() - - lua.execute( - textwrap.dedent( - """\ - function module(name) - end - - """ - ) - ) - - bind_gettext = lua.eval( - textwrap.dedent( - """\ - function(py_gettext) - package.preload["i_18n"] = function() - return { - translate = py_gettext - } - end - end - - """ - ) - ) - - try: - translator = gettext.translation( - "messages", path / "l10n", languages=["en"] - ) - - def translate(message_name: str) -> str: - if not message_name: - return message_name - return translator.gettext(message_name) - - except FileNotFoundError: - # TheChannel has no locale data for English. - def translate(message_name: str) -> str: - return message_name - - bind_gettext(translate) - - src = beacons_lua.read_text() - lua.execute(src) - - beacon_types_map: Dict[int, BeaconType] = {} - for beacon_type in BeaconType: - beacon_value = lua.eval(beacon_type.name) - beacon_types_map[beacon_value] = beacon_type - - beacons = lua.eval("beacons") - for beacon in beacons.values(): - beacon_type_lua = beacon["type"] - if beacon_type_lua not in beacon_types_map: - beacon_types_path = ( - dcs_path / "MissionEditor/modules/me_beaconsInfo.lua" - ) - raise KeyError( - f"Unknown beacon type {beacon_type_lua}. Check that all " - f"beacon types in {beacon_types_path} are present in " - f"{BeaconType.__class__.__name__}" - ) - beacon_type = beacon_types_map[beacon_type_lua] - - yield beacon["beaconId"], Beacon( - beacon["display_name"], - beacon["callsign"], - beacon_type, - convert_lua_frequency(beacon["frequency"]), - getattr(beacon, "channel", None), - ) - - -class Importer: - """Imports beacon definitions from each available terrain mod. - - Only beacons for maps owned by the user can be imported. Other maps that - have been previously imported will not be disturbed. - """ - - def __init__(self, dcs_path: Path, export_dir: Path) -> None: - self.dcs_path = dcs_path - self.export_dir = export_dir - - def run(self) -> None: - """Exports the beacons for each available terrain mod.""" - terrains_path = self.dcs_path / "Mods" / "terrains" - self.export_dir.mkdir(parents=True, exist_ok=True) - for terrain in terrains_path.iterdir(): - beacons = beacons_from_terrain(self.dcs_path, terrain) - self.export_beacons(terrain.name, beacons) - - def export_beacons( - self, terrain: str, beacons: Iterable[tuple[str, Beacon]] - ) -> None: - terrain_py_path = self.export_dir / f"{terrain.lower()}.json" - - terrain_py_path.write_text( - json.dumps({bid: dataclasses.asdict(b) for bid, b in beacons}, indent=True) - ) - - -def parse_args() -> argparse.Namespace: - """Parses and returns command line arguments.""" - parser = argparse.ArgumentParser() - - def resolved_path(val: str) -> Path: - """Returns the given string as a fully resolved Path.""" - return Path(val).resolve() - - parser.add_argument( - "--export-to", - type=resolved_path, - default=EXPORT_DIR, - help="Output directory for generated JSON files.", - ) - - parser.add_argument( - "dcs_path", - metavar="DCS_PATH", - type=resolved_path, - help="Path to DCS installation.", - ) - - return parser.parse_args() - - -def main() -> None: - """Program entry point.""" - logging.basicConfig(level=logging.DEBUG) - args = parse_args() - Importer(args.dcs_path, args.export_to).run() - - -if __name__ == "__main__": - main() diff --git a/resources/tools/loadoutviewer.py b/resources/tools/loadoutviewer.py deleted file mode 100644 index 22d707f3f..000000000 --- a/resources/tools/loadoutviewer.py +++ /dev/null @@ -1,134 +0,0 @@ -"""Command-line utility for displaying human readable loadout configurations.""" -import argparse -import sys -from collections.abc import Iterator -from pathlib import Path -from typing import Type - -from dcs.helicopters import helicopter_map -from dcs.planes import plane_map -from dcs.unittype import FlyingType - -from game import persistence -from game.ato import FlightType -from game.ato.loadouts import Loadout -from game.dcs.aircrafttype import AircraftType - -# TODO: Move this logic out of the UI. -from qt_ui import liberation_install -from qt_ui.main import inject_custom_payloads - - -def non_empty_loadouts_for( - aircraft: Type[FlyingType], -) -> Iterator[tuple[FlightType, Loadout]]: - for task in FlightType: - try: - loadout = Loadout.default_for_task_and_aircraft(task, aircraft) - except KeyError: - # Not all aircraft have a unitPayloads field. This should maybe be handled - # in pydcs, but I'm not sure about the cause. For now, just ignore the field - # since we can be less robust in optional tooling. - continue - - if loadout.name != "Empty": - yield task, loadout - - -def print_pylons(loadout: Loadout, prefix: str = "\t") -> None: - pylons = dict(sorted(loadout.pylons.items())) - for pylon_id, weapon in pylons.items(): - if weapon is not None: - print(f"{prefix}{pylon_id}: {weapon.name}") - - -def show_all_loadouts(aircraft: Type[FlyingType]) -> None: - loadouts = list(non_empty_loadouts_for(aircraft)) - if not loadouts: - return - - print(f"Loadouts for {aircraft.id}:") - for task, loadout in loadouts: - print(f"\t{task.value}: {loadout.name}") - print_pylons(loadout, prefix="\t\t") - - -def task_by_name(name: str) -> FlightType: - for task in FlightType: - if task.value == name: - return task - raise KeyError(f"No FlightType named {name}") - - -def show_single_loadout(aircraft: Type[FlyingType], task_name: str) -> None: - task = task_by_name(task_name) - try: - loadout = Loadout.default_for_task_and_aircraft(task, aircraft) - except KeyError: - # Not all aircraft have a unitPayloads field. This should maybe be handled - # in pydcs, but I'm not sure about the cause. For now, just ignore the field - # since we can be less robust in optional tooling. - return - if loadout.pylons: - print(f"{aircraft.id} {loadout.name}:") - print_pylons(loadout) - - -def show_loadouts_for(aircraft: Type[FlyingType], task_name: str | None) -> None: - if task_name is None: - show_all_loadouts(aircraft) - else: - show_single_loadout(aircraft, task_name) - - -def show_all_aircraft(task_name: str | None) -> None: - for aircraft in AircraftType.each_dcs_type(): - show_loadouts_for(aircraft, task_name) - - -def show_single_aircraft(aircraft_id: str, task_name: str | None) -> None: - try: - aircraft: Type[FlyingType] = plane_map[aircraft_id] - except KeyError: - aircraft = helicopter_map[aircraft_id] - show_loadouts_for(aircraft, task_name) - - -def main() -> None: - parser = argparse.ArgumentParser() - - parser.add_argument( - "--aircraft-id", - help=( - "ID of the aircraft to display loadouts for. By default all aircraft will " - + "be displayed." - ), - ) - - parser.add_argument( - "--task", - help=( - "Name of the mission type to display. By default loadouts for all mission " - + "types will be displayed." - ), - ) - - args = parser.parse_args() - - first_start = liberation_install.init() - if first_start: - sys.exit( - "Cannot view payloads without configuring DCS Liberation. Start the UI for " - "the first run configuration." - ) - - inject_custom_payloads(Path(persistence.base_path())) - - if args.aircraft_id is None: - show_all_aircraft(args.task) - else: - show_single_aircraft(args.aircraft_id, args.task) - - -if __name__ == "__main__": - main() diff --git a/resources/tools/marianaislands_terrain.miz b/resources/tools/marianaislands_terrain.miz deleted file mode 100644 index 696901913..000000000 Binary files a/resources/tools/marianaislands_terrain.miz and /dev/null differ diff --git a/resources/tools/miz_diff.py b/resources/tools/miz_diff.py deleted file mode 100644 index eb1c1076f..000000000 --- a/resources/tools/miz_diff.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys - -from dcs.lua.parse import * -from dcs.lua.serialize import * - -a = loads(open(sys.argv[1], "r").read()) -b = loads(open(sys.argv[2], "r").read()) - - -def get(a, k): - b = a - for x in k.strip().split(" "): - if isinstance(a, dict): - y = a - a = a.get(x, None) - if a is None: - try: - a = y.get(int(x), None) - except: - pass - else: - break - if a is None: - pass - return a - - -def cycle(kk, ref, v): - if isinstance(v, dict): - for k, v in v.items(): - cycle(kk + " " + str(k), ref, v) - elif isinstance(v, list): - for i, v in enumerate(v): - cycle(kk + " " + str(i), ref, v) - else: - if get(ref, kk) != v: - print(kk) - print(v) - print(get(ref, kk)) - - -cycle("", a, b) diff --git a/resources/tools/mkrelease.py b/resources/tools/mkrelease.py deleted file mode 100644 index 1704dda14..000000000 --- a/resources/tools/mkrelease.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -from pathlib import Path -import shutil - -THIS_DIR = Path(__file__).resolve() -SRC_DIR = THIS_DIR.parents[1] - - -IGNORED_PATHS = [ - "__pycache__", - ".gitignore", - ".git", - ".idea", - ".DS_Store", - "requirements.txt", - "build", - "venv", -] - - -def _zip_dir(archive, path): - for path, directories, files in os.walk(path): - is_ignored = False - for ignored_path in IGNORED_PATHS: - if ignored_path in path: - is_ignored = True - break - - if is_ignored: - continue - - for file in files: - if file in IGNORED_PATHS: - continue - archive.write(os.path.join(path, file)) - - -def main(): - try: - shutil.rmtree("./dist") - except FileNotFoundError: - pass - os.system("pyinstaller.exe --clean pyinstaller.spec") - - -if __name__ == "__main__": - main() diff --git a/resources/tools/nev_terrain.miz b/resources/tools/nev_terrain.miz deleted file mode 100644 index dec5094f3..000000000 Binary files a/resources/tools/nev_terrain.miz and /dev/null differ diff --git a/resources/tools/normandy_terrain.miz b/resources/tools/normandy_terrain.miz deleted file mode 100644 index 9dbc18d4f..000000000 Binary files a/resources/tools/normandy_terrain.miz and /dev/null differ diff --git a/resources/tools/syria_terrain.miz b/resources/tools/syria_terrain.miz deleted file mode 100644 index f169d31c2..000000000 Binary files a/resources/tools/syria_terrain.miz and /dev/null differ diff --git a/resources/ui/airbase.png b/resources/ui/airbase.png deleted file mode 100644 index 9fe369459..000000000 Binary files a/resources/ui/airbase.png and /dev/null differ diff --git a/resources/ui/conditions/light/timeofday/dawn.png b/resources/ui/conditions/light/timeofday/dawn.png deleted file mode 100644 index f2be3bc08..000000000 Binary files a/resources/ui/conditions/light/timeofday/dawn.png and /dev/null differ diff --git a/resources/ui/conditions/light/timeofday/day.png b/resources/ui/conditions/light/timeofday/day.png deleted file mode 100644 index f215867e5..000000000 Binary files a/resources/ui/conditions/light/timeofday/day.png and /dev/null differ diff --git a/resources/ui/conditions/light/timeofday/dusk.png b/resources/ui/conditions/light/timeofday/dusk.png deleted file mode 100644 index 152f98e1c..000000000 Binary files a/resources/ui/conditions/light/timeofday/dusk.png and /dev/null differ diff --git a/resources/ui/conditions/light/timeofday/night.png b/resources/ui/conditions/light/timeofday/night.png deleted file mode 100644 index 3ff11ed90..000000000 Binary files a/resources/ui/conditions/light/timeofday/night.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-clear.png b/resources/ui/conditions/light/weather/day-clear.png deleted file mode 100644 index f215867e5..000000000 Binary files a/resources/ui/conditions/light/weather/day-clear.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-cloudy-fog.png b/resources/ui/conditions/light/weather/day-cloudy-fog.png deleted file mode 100644 index ebee0024d..000000000 Binary files a/resources/ui/conditions/light/weather/day-cloudy-fog.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-fog.png b/resources/ui/conditions/light/weather/day-fog.png deleted file mode 100644 index c2868d7b9..000000000 Binary files a/resources/ui/conditions/light/weather/day-fog.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-partly-cloudy.png b/resources/ui/conditions/light/weather/day-partly-cloudy.png deleted file mode 100644 index 6eb077519..000000000 Binary files a/resources/ui/conditions/light/weather/day-partly-cloudy.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-rain.png b/resources/ui/conditions/light/weather/day-rain.png deleted file mode 100644 index f79a52895..000000000 Binary files a/resources/ui/conditions/light/weather/day-rain.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-thunderstorm.png b/resources/ui/conditions/light/weather/day-thunderstorm.png deleted file mode 100644 index 61fcc700f..000000000 Binary files a/resources/ui/conditions/light/weather/day-thunderstorm.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/day-totally-cloud.png b/resources/ui/conditions/light/weather/day-totally-cloud.png deleted file mode 100644 index e56dcf903..000000000 Binary files a/resources/ui/conditions/light/weather/day-totally-cloud.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-clear.png b/resources/ui/conditions/light/weather/night-clear.png deleted file mode 100644 index eb4da38ed..000000000 Binary files a/resources/ui/conditions/light/weather/night-clear.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-cloudy-fog.png b/resources/ui/conditions/light/weather/night-cloudy-fog.png deleted file mode 100644 index ebee0024d..000000000 Binary files a/resources/ui/conditions/light/weather/night-cloudy-fog.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-fog.png b/resources/ui/conditions/light/weather/night-fog.png deleted file mode 100644 index bab41451b..000000000 Binary files a/resources/ui/conditions/light/weather/night-fog.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-partly-cloudy.png b/resources/ui/conditions/light/weather/night-partly-cloudy.png deleted file mode 100644 index 9c442a00b..000000000 Binary files a/resources/ui/conditions/light/weather/night-partly-cloudy.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-rain.png b/resources/ui/conditions/light/weather/night-rain.png deleted file mode 100644 index ac2adbd17..000000000 Binary files a/resources/ui/conditions/light/weather/night-rain.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-thundersotrm.png b/resources/ui/conditions/light/weather/night-thundersotrm.png deleted file mode 100644 index 7c65921d8..000000000 Binary files a/resources/ui/conditions/light/weather/night-thundersotrm.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/night-totally-cloud.png b/resources/ui/conditions/light/weather/night-totally-cloud.png deleted file mode 100644 index e56dcf903..000000000 Binary files a/resources/ui/conditions/light/weather/night-totally-cloud.png and /dev/null differ diff --git a/resources/ui/conditions/light/weather/winds.png b/resources/ui/conditions/light/weather/winds.png deleted file mode 100644 index 06afc80d8..000000000 Binary files a/resources/ui/conditions/light/weather/winds.png and /dev/null differ diff --git a/resources/ui/conditions/medium/timeofday/dawn.png b/resources/ui/conditions/medium/timeofday/dawn.png deleted file mode 100644 index f492b7780..000000000 Binary files a/resources/ui/conditions/medium/timeofday/dawn.png and /dev/null differ diff --git a/resources/ui/conditions/medium/timeofday/day.png b/resources/ui/conditions/medium/timeofday/day.png deleted file mode 100644 index 350f98cd7..000000000 Binary files a/resources/ui/conditions/medium/timeofday/day.png and /dev/null differ diff --git a/resources/ui/conditions/medium/timeofday/dusk.png b/resources/ui/conditions/medium/timeofday/dusk.png deleted file mode 100644 index 73d4dd1d4..000000000 Binary files a/resources/ui/conditions/medium/timeofday/dusk.png and /dev/null differ diff --git a/resources/ui/conditions/medium/timeofday/night.png b/resources/ui/conditions/medium/timeofday/night.png deleted file mode 100644 index 3401bf7fa..000000000 Binary files a/resources/ui/conditions/medium/timeofday/night.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-clear.png b/resources/ui/conditions/medium/weather/day-clear.png deleted file mode 100644 index 128cf9f01..000000000 Binary files a/resources/ui/conditions/medium/weather/day-clear.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-cloudy-fog.png b/resources/ui/conditions/medium/weather/day-cloudy-fog.png deleted file mode 100644 index 210cfa4c6..000000000 Binary files a/resources/ui/conditions/medium/weather/day-cloudy-fog.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-fog.png b/resources/ui/conditions/medium/weather/day-fog.png deleted file mode 100644 index 8053fa587..000000000 Binary files a/resources/ui/conditions/medium/weather/day-fog.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-partly-cloudy.png b/resources/ui/conditions/medium/weather/day-partly-cloudy.png deleted file mode 100644 index 4f270a3f3..000000000 Binary files a/resources/ui/conditions/medium/weather/day-partly-cloudy.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-rain.png b/resources/ui/conditions/medium/weather/day-rain.png deleted file mode 100644 index 1984bb6d3..000000000 Binary files a/resources/ui/conditions/medium/weather/day-rain.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-thunderstorm.png b/resources/ui/conditions/medium/weather/day-thunderstorm.png deleted file mode 100644 index 13627e46b..000000000 Binary files a/resources/ui/conditions/medium/weather/day-thunderstorm.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/day-totally-cloud.png b/resources/ui/conditions/medium/weather/day-totally-cloud.png deleted file mode 100644 index fe042f5c7..000000000 Binary files a/resources/ui/conditions/medium/weather/day-totally-cloud.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-clear.png b/resources/ui/conditions/medium/weather/night-clear.png deleted file mode 100644 index a657f6f03..000000000 Binary files a/resources/ui/conditions/medium/weather/night-clear.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-cloudy-fog.png b/resources/ui/conditions/medium/weather/night-cloudy-fog.png deleted file mode 100644 index 79a7058d0..000000000 Binary files a/resources/ui/conditions/medium/weather/night-cloudy-fog.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-fog.png b/resources/ui/conditions/medium/weather/night-fog.png deleted file mode 100644 index 8cabd603a..000000000 Binary files a/resources/ui/conditions/medium/weather/night-fog.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-partly-cloudy.png b/resources/ui/conditions/medium/weather/night-partly-cloudy.png deleted file mode 100644 index b56b89c84..000000000 Binary files a/resources/ui/conditions/medium/weather/night-partly-cloudy.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-rain.png b/resources/ui/conditions/medium/weather/night-rain.png deleted file mode 100644 index 94b8e9807..000000000 Binary files a/resources/ui/conditions/medium/weather/night-rain.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-thundersotrm.png b/resources/ui/conditions/medium/weather/night-thundersotrm.png deleted file mode 100644 index 5a549cb5d..000000000 Binary files a/resources/ui/conditions/medium/weather/night-thundersotrm.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/night-totally-cloud.png b/resources/ui/conditions/medium/weather/night-totally-cloud.png deleted file mode 100644 index 7d5f8718a..000000000 Binary files a/resources/ui/conditions/medium/weather/night-totally-cloud.png and /dev/null differ diff --git a/resources/ui/conditions/medium/weather/winds.png b/resources/ui/conditions/medium/weather/winds.png deleted file mode 100644 index c14eda8a5..000000000 Binary files a/resources/ui/conditions/medium/weather/winds.png and /dev/null differ diff --git a/resources/ui/conflict.png b/resources/ui/conflict.png deleted file mode 100644 index ee2336374..000000000 Binary files a/resources/ui/conflict.png and /dev/null differ diff --git a/resources/ui/debriefing.png b/resources/ui/debriefing.png deleted file mode 100644 index ceda551fd..000000000 Binary files a/resources/ui/debriefing.png and /dev/null differ diff --git a/resources/ui/events/air_intercept.png b/resources/ui/events/air_intercept.png deleted file mode 100644 index d5277556c..000000000 Binary files a/resources/ui/events/air_intercept.png and /dev/null differ diff --git a/resources/ui/events/attack.PNG b/resources/ui/events/attack.PNG deleted file mode 100644 index 6034304c4..000000000 Binary files a/resources/ui/events/attack.PNG and /dev/null differ diff --git a/resources/ui/events/capture.PNG b/resources/ui/events/capture.PNG deleted file mode 100644 index 497fd98dc..000000000 Binary files a/resources/ui/events/capture.PNG and /dev/null differ diff --git a/resources/ui/events/convoy.png b/resources/ui/events/convoy.png deleted file mode 100644 index 94acd7e03..000000000 Binary files a/resources/ui/events/convoy.png and /dev/null differ diff --git a/resources/ui/events/delivery.PNG b/resources/ui/events/delivery.PNG deleted file mode 100644 index b06ce953f..000000000 Binary files a/resources/ui/events/delivery.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/air_intercept.png b/resources/ui/events/icons-med/air_intercept.png deleted file mode 100644 index d5277556c..000000000 Binary files a/resources/ui/events/icons-med/air_intercept.png and /dev/null differ diff --git a/resources/ui/events/icons-med/attack.PNG b/resources/ui/events/icons-med/attack.PNG deleted file mode 100644 index 6034304c4..000000000 Binary files a/resources/ui/events/icons-med/attack.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/capture.PNG b/resources/ui/events/icons-med/capture.PNG deleted file mode 100644 index 497fd98dc..000000000 Binary files a/resources/ui/events/icons-med/capture.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/convoy.png b/resources/ui/events/icons-med/convoy.png deleted file mode 100644 index 94acd7e03..000000000 Binary files a/resources/ui/events/icons-med/convoy.png and /dev/null differ diff --git a/resources/ui/events/icons-med/delivery.PNG b/resources/ui/events/icons-med/delivery.PNG deleted file mode 100644 index b06ce953f..000000000 Binary files a/resources/ui/events/icons-med/delivery.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/infantry.PNG b/resources/ui/events/icons-med/infantry.PNG deleted file mode 100644 index 4deace153..000000000 Binary files a/resources/ui/events/icons-med/infantry.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/insurgent_attack.PNG b/resources/ui/events/icons-med/insurgent_attack.PNG deleted file mode 100644 index 8322637b1..000000000 Binary files a/resources/ui/events/icons-med/insurgent_attack.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/naval_intercept.PNG b/resources/ui/events/icons-med/naval_intercept.PNG deleted file mode 100644 index 6206da268..000000000 Binary files a/resources/ui/events/icons-med/naval_intercept.PNG and /dev/null differ diff --git a/resources/ui/events/icons-med/strike.PNG b/resources/ui/events/icons-med/strike.PNG deleted file mode 100644 index 5eb982fff..000000000 Binary files a/resources/ui/events/icons-med/strike.PNG and /dev/null differ diff --git a/resources/ui/events/infantry.PNG b/resources/ui/events/infantry.PNG deleted file mode 100644 index 4deace153..000000000 Binary files a/resources/ui/events/infantry.PNG and /dev/null differ diff --git a/resources/ui/events/insurgent_attack.PNG b/resources/ui/events/insurgent_attack.PNG deleted file mode 100644 index 8322637b1..000000000 Binary files a/resources/ui/events/insurgent_attack.PNG and /dev/null differ diff --git a/resources/ui/events/naval_intercept.PNG b/resources/ui/events/naval_intercept.PNG deleted file mode 100644 index 6206da268..000000000 Binary files a/resources/ui/events/naval_intercept.PNG and /dev/null differ diff --git a/resources/ui/events/originals/air_intercept.png b/resources/ui/events/originals/air_intercept.png deleted file mode 100644 index 1b66f0f66..000000000 Binary files a/resources/ui/events/originals/air_intercept.png and /dev/null differ diff --git a/resources/ui/events/originals/attack.PNG b/resources/ui/events/originals/attack.PNG deleted file mode 100644 index eb7169bff..000000000 Binary files a/resources/ui/events/originals/attack.PNG and /dev/null differ diff --git a/resources/ui/events/originals/capture.PNG b/resources/ui/events/originals/capture.PNG deleted file mode 100644 index 98ab3cd9c..000000000 Binary files a/resources/ui/events/originals/capture.PNG and /dev/null differ diff --git a/resources/ui/events/originals/convoy.png b/resources/ui/events/originals/convoy.png deleted file mode 100644 index f2e31f6e3..000000000 Binary files a/resources/ui/events/originals/convoy.png and /dev/null differ diff --git a/resources/ui/events/originals/delivery.PNG b/resources/ui/events/originals/delivery.PNG deleted file mode 100644 index 3a2916164..000000000 Binary files a/resources/ui/events/originals/delivery.PNG and /dev/null differ diff --git a/resources/ui/events/originals/infantry.PNG b/resources/ui/events/originals/infantry.PNG deleted file mode 100644 index a3dd2b385..000000000 Binary files a/resources/ui/events/originals/infantry.PNG and /dev/null differ diff --git a/resources/ui/events/originals/insurgent_attack.PNG b/resources/ui/events/originals/insurgent_attack.PNG deleted file mode 100644 index 44f7ea625..000000000 Binary files a/resources/ui/events/originals/insurgent_attack.PNG and /dev/null differ diff --git a/resources/ui/events/originals/naval_intercept.PNG b/resources/ui/events/originals/naval_intercept.PNG deleted file mode 100644 index d121b471a..000000000 Binary files a/resources/ui/events/originals/naval_intercept.PNG and /dev/null differ diff --git a/resources/ui/events/originals/strike.PNG b/resources/ui/events/originals/strike.PNG deleted file mode 100644 index 73eb2c67e..000000000 Binary files a/resources/ui/events/originals/strike.PNG and /dev/null differ diff --git a/resources/ui/events/strike.PNG b/resources/ui/events/strike.PNG deleted file mode 100644 index 5eb982fff..000000000 Binary files a/resources/ui/events/strike.PNG and /dev/null differ diff --git a/resources/ui/fob.png b/resources/ui/fob.png deleted file mode 100644 index a64ae0734..000000000 Binary files a/resources/ui/fob.png and /dev/null differ diff --git a/resources/ui/heliport.png b/resources/ui/heliport.png deleted file mode 100644 index 17f759de5..000000000 Binary files a/resources/ui/heliport.png and /dev/null differ diff --git a/resources/ui/loader.gif b/resources/ui/loader.gif deleted file mode 100644 index 1a29732d2..000000000 Binary files a/resources/ui/loader.gif and /dev/null differ diff --git a/resources/ui/misc/all-flight-paths.png b/resources/ui/misc/all-flight-paths.png deleted file mode 100644 index 1e0bae20e..000000000 Binary files a/resources/ui/misc/all-flight-paths.png and /dev/null differ diff --git a/resources/ui/misc/blue-sam.png b/resources/ui/misc/blue-sam.png deleted file mode 100644 index 4be436621..000000000 Binary files a/resources/ui/misc/blue-sam.png and /dev/null differ diff --git a/resources/ui/misc/cheat.png b/resources/ui/misc/cheat.png deleted file mode 100644 index af0270cbe..000000000 Binary files a/resources/ui/misc/cheat.png and /dev/null differ diff --git a/resources/ui/misc/dark/bug.png b/resources/ui/misc/dark/bug.png deleted file mode 100644 index e1049d463..000000000 Binary files a/resources/ui/misc/dark/bug.png and /dev/null differ diff --git a/resources/ui/misc/dark/cheat.png b/resources/ui/misc/dark/cheat.png deleted file mode 100644 index b8e15ba13..000000000 Binary files a/resources/ui/misc/dark/cheat.png and /dev/null differ diff --git a/resources/ui/misc/dark/discord.png b/resources/ui/misc/dark/discord.png deleted file mode 100644 index 97739171e..000000000 Binary files a/resources/ui/misc/dark/discord.png and /dev/null differ diff --git a/resources/ui/misc/dark/generator.png b/resources/ui/misc/dark/generator.png deleted file mode 100644 index c975dbcab..000000000 Binary files a/resources/ui/misc/dark/generator.png and /dev/null differ diff --git a/resources/ui/misc/dark/github.png b/resources/ui/misc/dark/github.png deleted file mode 100644 index 84b8dd84c..000000000 Binary files a/resources/ui/misc/dark/github.png and /dev/null differ diff --git a/resources/ui/misc/dark/hourglass.png b/resources/ui/misc/dark/hourglass.png deleted file mode 100644 index c28e9ad57..000000000 Binary files a/resources/ui/misc/dark/hourglass.png and /dev/null differ diff --git a/resources/ui/misc/dark/missile.png b/resources/ui/misc/dark/missile.png deleted file mode 100644 index 777ac5539..000000000 Binary files a/resources/ui/misc/dark/missile.png and /dev/null differ diff --git a/resources/ui/misc/dark/money_icon.png b/resources/ui/misc/dark/money_icon.png deleted file mode 100644 index 6cc580955..000000000 Binary files a/resources/ui/misc/dark/money_icon.png and /dev/null differ diff --git a/resources/ui/misc/dark/new.png b/resources/ui/misc/dark/new.png deleted file mode 100644 index c94e0b6a6..000000000 Binary files a/resources/ui/misc/dark/new.png and /dev/null differ diff --git a/resources/ui/misc/dark/notes.png b/resources/ui/misc/dark/notes.png deleted file mode 100644 index 2bb0f1eb5..000000000 Binary files a/resources/ui/misc/dark/notes.png and /dev/null differ diff --git a/resources/ui/misc/dark/open.png b/resources/ui/misc/dark/open.png deleted file mode 100644 index 2106a552d..000000000 Binary files a/resources/ui/misc/dark/open.png and /dev/null differ diff --git a/resources/ui/misc/dark/ordnance_icon.png b/resources/ui/misc/dark/ordnance_icon.png deleted file mode 100644 index 8c1660ff2..000000000 Binary files a/resources/ui/misc/dark/ordnance_icon.png and /dev/null differ diff --git a/resources/ui/misc/dark/proceed.png b/resources/ui/misc/dark/proceed.png deleted file mode 100644 index b6e41e2d6..000000000 Binary files a/resources/ui/misc/dark/proceed.png and /dev/null differ diff --git a/resources/ui/misc/dark/reload.png b/resources/ui/misc/dark/reload.png deleted file mode 100644 index 8d42d6714..000000000 Binary files a/resources/ui/misc/dark/reload.png and /dev/null differ diff --git a/resources/ui/misc/dark/save.png b/resources/ui/misc/dark/save.png deleted file mode 100644 index 867904c41..000000000 Binary files a/resources/ui/misc/dark/save.png and /dev/null differ diff --git a/resources/ui/misc/dark/settings.png b/resources/ui/misc/dark/settings.png deleted file mode 100644 index 7d06d66a5..000000000 Binary files a/resources/ui/misc/dark/settings.png and /dev/null differ diff --git a/resources/ui/misc/dark/statistics.png b/resources/ui/misc/dark/statistics.png deleted file mode 100644 index ebc0f7f3f..000000000 Binary files a/resources/ui/misc/dark/statistics.png and /dev/null differ diff --git a/resources/ui/misc/detection-sam.png b/resources/ui/misc/detection-sam.png deleted file mode 100644 index 033ce3495..000000000 Binary files a/resources/ui/misc/detection-sam.png and /dev/null differ diff --git a/resources/ui/misc/discord.png b/resources/ui/misc/discord.png deleted file mode 100644 index 59371f023..000000000 Binary files a/resources/ui/misc/discord.png and /dev/null differ diff --git a/resources/ui/misc/flight-path.png b/resources/ui/misc/flight-path.png deleted file mode 100644 index 5e43c6390..000000000 Binary files a/resources/ui/misc/flight-path.png and /dev/null differ diff --git a/resources/ui/misc/generator.png b/resources/ui/misc/generator.png deleted file mode 100644 index d5ad07218..000000000 Binary files a/resources/ui/misc/generator.png and /dev/null differ diff --git a/resources/ui/misc/github.png b/resources/ui/misc/github.png deleted file mode 100644 index 2668dabd8..000000000 Binary files a/resources/ui/misc/github.png and /dev/null differ diff --git a/resources/ui/misc/hangar.png b/resources/ui/misc/hangar.png deleted file mode 100644 index dc98f5599..000000000 Binary files a/resources/ui/misc/hangar.png and /dev/null differ diff --git a/resources/ui/misc/heading.png b/resources/ui/misc/heading.png deleted file mode 100644 index f05288cfb..000000000 Binary files a/resources/ui/misc/heading.png and /dev/null differ diff --git a/resources/ui/misc/hide-flight-path.png b/resources/ui/misc/hide-flight-path.png deleted file mode 100644 index 94eb9731f..000000000 Binary files a/resources/ui/misc/hide-flight-path.png and /dev/null differ diff --git a/resources/ui/misc/hourglass.png b/resources/ui/misc/hourglass.png deleted file mode 100644 index 73745fc58..000000000 Binary files a/resources/ui/misc/hourglass.png and /dev/null differ diff --git a/resources/ui/misc/light/arrows-h.png b/resources/ui/misc/light/arrows-h.png deleted file mode 100644 index 40ccd57ea..000000000 Binary files a/resources/ui/misc/light/arrows-h.png and /dev/null differ diff --git a/resources/ui/misc/light/bug.png b/resources/ui/misc/light/bug.png deleted file mode 100644 index 7c5a064a1..000000000 Binary files a/resources/ui/misc/light/bug.png and /dev/null differ diff --git a/resources/ui/misc/light/bullseye.png b/resources/ui/misc/light/bullseye.png deleted file mode 100644 index 7fc4519db..000000000 Binary files a/resources/ui/misc/light/bullseye.png and /dev/null differ diff --git a/resources/ui/misc/light/cheat.png b/resources/ui/misc/light/cheat.png deleted file mode 100644 index af0270cbe..000000000 Binary files a/resources/ui/misc/light/cheat.png and /dev/null differ diff --git a/resources/ui/misc/light/circle-o-notch.png b/resources/ui/misc/light/circle-o-notch.png deleted file mode 100644 index 81290dd05..000000000 Binary files a/resources/ui/misc/light/circle-o-notch.png and /dev/null differ diff --git a/resources/ui/misc/light/circle-o.png b/resources/ui/misc/light/circle-o.png deleted file mode 100644 index 6bbc1a9e9..000000000 Binary files a/resources/ui/misc/light/circle-o.png and /dev/null differ diff --git a/resources/ui/misc/light/circle-thin.png b/resources/ui/misc/light/circle-thin.png deleted file mode 100644 index e04e126a8..000000000 Binary files a/resources/ui/misc/light/circle-thin.png and /dev/null differ diff --git a/resources/ui/misc/light/circle.png b/resources/ui/misc/light/circle.png deleted file mode 100644 index 5ed342b29..000000000 Binary files a/resources/ui/misc/light/circle.png and /dev/null differ diff --git a/resources/ui/misc/light/discord.png b/resources/ui/misc/light/discord.png deleted file mode 100644 index 59371f023..000000000 Binary files a/resources/ui/misc/light/discord.png and /dev/null differ diff --git a/resources/ui/misc/light/dot-circle-o.png b/resources/ui/misc/light/dot-circle-o.png deleted file mode 100644 index 7dfd0f510..000000000 Binary files a/resources/ui/misc/light/dot-circle-o.png and /dev/null differ diff --git a/resources/ui/misc/light/eraser.png b/resources/ui/misc/light/eraser.png deleted file mode 100644 index 730e55ff6..000000000 Binary files a/resources/ui/misc/light/eraser.png and /dev/null differ diff --git a/resources/ui/misc/light/fighter-jet.png b/resources/ui/misc/light/fighter-jet.png deleted file mode 100644 index 0bee27328..000000000 Binary files a/resources/ui/misc/light/fighter-jet.png and /dev/null differ diff --git a/resources/ui/misc/light/flag.png b/resources/ui/misc/light/flag.png deleted file mode 100644 index 6f0a38fdd..000000000 Binary files a/resources/ui/misc/light/flag.png and /dev/null differ diff --git a/resources/ui/misc/light/generator.png b/resources/ui/misc/light/generator.png deleted file mode 100644 index d5ad07218..000000000 Binary files a/resources/ui/misc/light/generator.png and /dev/null differ diff --git a/resources/ui/misc/light/github.png b/resources/ui/misc/light/github.png deleted file mode 100644 index 2668dabd8..000000000 Binary files a/resources/ui/misc/light/github.png and /dev/null differ diff --git a/resources/ui/misc/light/hourglass.png b/resources/ui/misc/light/hourglass.png deleted file mode 100644 index 73745fc58..000000000 Binary files a/resources/ui/misc/light/hourglass.png and /dev/null differ diff --git a/resources/ui/misc/light/industry.png b/resources/ui/misc/light/industry.png deleted file mode 100644 index cc37442b8..000000000 Binary files a/resources/ui/misc/light/industry.png and /dev/null differ diff --git a/resources/ui/misc/light/info.png b/resources/ui/misc/light/info.png deleted file mode 100644 index 67e9088f8..000000000 Binary files a/resources/ui/misc/light/info.png and /dev/null differ diff --git a/resources/ui/misc/light/map-marker.png b/resources/ui/misc/light/map-marker.png deleted file mode 100644 index 0f71dfa0f..000000000 Binary files a/resources/ui/misc/light/map-marker.png and /dev/null differ diff --git a/resources/ui/misc/light/map-o.png b/resources/ui/misc/light/map-o.png deleted file mode 100644 index 9474954e7..000000000 Binary files a/resources/ui/misc/light/map-o.png and /dev/null differ diff --git a/resources/ui/misc/light/map.png b/resources/ui/misc/light/map.png deleted file mode 100644 index b140a323f..000000000 Binary files a/resources/ui/misc/light/map.png and /dev/null differ diff --git a/resources/ui/misc/light/missile.png b/resources/ui/misc/light/missile.png deleted file mode 100644 index 086a43e7e..000000000 Binary files a/resources/ui/misc/light/missile.png and /dev/null differ diff --git a/resources/ui/misc/light/money_icon.png b/resources/ui/misc/light/money_icon.png deleted file mode 100644 index dc626090a..000000000 Binary files a/resources/ui/misc/light/money_icon.png and /dev/null differ diff --git a/resources/ui/misc/light/new.png b/resources/ui/misc/light/new.png deleted file mode 100644 index 3ff8a26cf..000000000 Binary files a/resources/ui/misc/light/new.png and /dev/null differ diff --git a/resources/ui/misc/light/notes.png b/resources/ui/misc/light/notes.png deleted file mode 100644 index 9f1300fc2..000000000 Binary files a/resources/ui/misc/light/notes.png and /dev/null differ diff --git a/resources/ui/misc/light/object-group.png b/resources/ui/misc/light/object-group.png deleted file mode 100644 index 65ff15733..000000000 Binary files a/resources/ui/misc/light/object-group.png and /dev/null differ diff --git a/resources/ui/misc/light/object-ungroup.png b/resources/ui/misc/light/object-ungroup.png deleted file mode 100644 index ddc9fe8d7..000000000 Binary files a/resources/ui/misc/light/object-ungroup.png and /dev/null differ diff --git a/resources/ui/misc/light/open.png b/resources/ui/misc/light/open.png deleted file mode 100644 index 97e15fdd2..000000000 Binary files a/resources/ui/misc/light/open.png and /dev/null differ diff --git a/resources/ui/misc/light/ordnance_icon.png b/resources/ui/misc/light/ordnance_icon.png deleted file mode 100644 index d9794c2c4..000000000 Binary files a/resources/ui/misc/light/ordnance_icon.png and /dev/null differ diff --git a/resources/ui/misc/light/plane.png b/resources/ui/misc/light/plane.png deleted file mode 100644 index 2c492f640..000000000 Binary files a/resources/ui/misc/light/plane.png and /dev/null differ diff --git a/resources/ui/misc/light/plugins.png b/resources/ui/misc/light/plugins.png deleted file mode 100644 index 568d9e958..000000000 Binary files a/resources/ui/misc/light/plugins.png and /dev/null differ diff --git a/resources/ui/misc/light/pluginsoptions.png b/resources/ui/misc/light/pluginsoptions.png deleted file mode 100644 index b9090ea22..000000000 Binary files a/resources/ui/misc/light/pluginsoptions.png and /dev/null differ diff --git a/resources/ui/misc/light/proceed.png b/resources/ui/misc/light/proceed.png deleted file mode 100644 index 22c9b89dd..000000000 Binary files a/resources/ui/misc/light/proceed.png and /dev/null differ diff --git a/resources/ui/misc/light/reload.png b/resources/ui/misc/light/reload.png deleted file mode 100644 index f5a4cf73c..000000000 Binary files a/resources/ui/misc/light/reload.png and /dev/null differ diff --git a/resources/ui/misc/light/save.png b/resources/ui/misc/light/save.png deleted file mode 100644 index 550b49633..000000000 Binary files a/resources/ui/misc/light/save.png and /dev/null differ diff --git a/resources/ui/misc/light/settings.png b/resources/ui/misc/light/settings.png deleted file mode 100644 index 058808b8f..000000000 Binary files a/resources/ui/misc/light/settings.png and /dev/null differ diff --git a/resources/ui/misc/light/statistics.png b/resources/ui/misc/light/statistics.png deleted file mode 100644 index 731c69c76..000000000 Binary files a/resources/ui/misc/light/statistics.png and /dev/null differ diff --git a/resources/ui/misc/medium/cheat.png b/resources/ui/misc/medium/cheat.png deleted file mode 100644 index 9001790c3..000000000 Binary files a/resources/ui/misc/medium/cheat.png and /dev/null differ diff --git a/resources/ui/misc/medium/discord.png b/resources/ui/misc/medium/discord.png deleted file mode 100644 index d2a43e0a8..000000000 Binary files a/resources/ui/misc/medium/discord.png and /dev/null differ diff --git a/resources/ui/misc/medium/generator.png b/resources/ui/misc/medium/generator.png deleted file mode 100644 index 3a2971a97..000000000 Binary files a/resources/ui/misc/medium/generator.png and /dev/null differ diff --git a/resources/ui/misc/medium/github.png b/resources/ui/misc/medium/github.png deleted file mode 100644 index 9e82b032e..000000000 Binary files a/resources/ui/misc/medium/github.png and /dev/null differ diff --git a/resources/ui/misc/medium/hourglass.png b/resources/ui/misc/medium/hourglass.png deleted file mode 100644 index d42e65b6a..000000000 Binary files a/resources/ui/misc/medium/hourglass.png and /dev/null differ diff --git a/resources/ui/misc/medium/missile.png b/resources/ui/misc/medium/missile.png deleted file mode 100644 index 5fb0c6916..000000000 Binary files a/resources/ui/misc/medium/missile.png and /dev/null differ diff --git a/resources/ui/misc/medium/money_icon.png b/resources/ui/misc/medium/money_icon.png deleted file mode 100644 index 0f81d4d28..000000000 Binary files a/resources/ui/misc/medium/money_icon.png and /dev/null differ diff --git a/resources/ui/misc/medium/new.png b/resources/ui/misc/medium/new.png deleted file mode 100644 index 363509e21..000000000 Binary files a/resources/ui/misc/medium/new.png and /dev/null differ diff --git a/resources/ui/misc/medium/open.png b/resources/ui/misc/medium/open.png deleted file mode 100644 index 5908bd44a..000000000 Binary files a/resources/ui/misc/medium/open.png and /dev/null differ diff --git a/resources/ui/misc/medium/ordnance_icon.png b/resources/ui/misc/medium/ordnance_icon.png deleted file mode 100644 index ef40da1da..000000000 Binary files a/resources/ui/misc/medium/ordnance_icon.png and /dev/null differ diff --git a/resources/ui/misc/medium/proceed.png b/resources/ui/misc/medium/proceed.png deleted file mode 100644 index 3158786be..000000000 Binary files a/resources/ui/misc/medium/proceed.png and /dev/null differ diff --git a/resources/ui/misc/medium/reload.png b/resources/ui/misc/medium/reload.png deleted file mode 100644 index 8cbb23fd8..000000000 Binary files a/resources/ui/misc/medium/reload.png and /dev/null differ diff --git a/resources/ui/misc/medium/save.png b/resources/ui/misc/medium/save.png deleted file mode 100644 index f6d4b63f4..000000000 Binary files a/resources/ui/misc/medium/save.png and /dev/null differ diff --git a/resources/ui/misc/medium/settings.png b/resources/ui/misc/medium/settings.png deleted file mode 100644 index 7aa676eee..000000000 Binary files a/resources/ui/misc/medium/settings.png and /dev/null differ diff --git a/resources/ui/misc/medium/statistics.png b/resources/ui/misc/medium/statistics.png deleted file mode 100644 index dba4e84ca..000000000 Binary files a/resources/ui/misc/medium/statistics.png and /dev/null differ diff --git a/resources/ui/misc/missile.png b/resources/ui/misc/missile.png deleted file mode 100644 index 086a43e7e..000000000 Binary files a/resources/ui/misc/missile.png and /dev/null differ diff --git a/resources/ui/misc/money_icon.png b/resources/ui/misc/money_icon.png deleted file mode 100644 index dc626090a..000000000 Binary files a/resources/ui/misc/money_icon.png and /dev/null differ diff --git a/resources/ui/misc/new.png b/resources/ui/misc/new.png deleted file mode 100644 index 3ff8a26cf..000000000 Binary files a/resources/ui/misc/new.png and /dev/null differ diff --git a/resources/ui/misc/notes.png b/resources/ui/misc/notes.png deleted file mode 100644 index 9f1300fc2..000000000 Binary files a/resources/ui/misc/notes.png and /dev/null differ diff --git a/resources/ui/misc/open.png b/resources/ui/misc/open.png deleted file mode 100644 index 97e15fdd2..000000000 Binary files a/resources/ui/misc/open.png and /dev/null differ diff --git a/resources/ui/misc/ordnance_icon.png b/resources/ui/misc/ordnance_icon.png deleted file mode 100644 index d9794c2c4..000000000 Binary files a/resources/ui/misc/ordnance_icon.png and /dev/null differ diff --git a/resources/ui/misc/original/cheat.png b/resources/ui/misc/original/cheat.png deleted file mode 100644 index cfc9d3e45..000000000 Binary files a/resources/ui/misc/original/cheat.png and /dev/null differ diff --git a/resources/ui/misc/original/generator.png b/resources/ui/misc/original/generator.png deleted file mode 100644 index 9d7074c1e..000000000 Binary files a/resources/ui/misc/original/generator.png and /dev/null differ diff --git a/resources/ui/misc/original/hourglass.png b/resources/ui/misc/original/hourglass.png deleted file mode 100644 index fff9a8f59..000000000 Binary files a/resources/ui/misc/original/hourglass.png and /dev/null differ diff --git a/resources/ui/misc/original/missile.png b/resources/ui/misc/original/missile.png deleted file mode 100644 index 61eadcd6d..000000000 Binary files a/resources/ui/misc/original/missile.png and /dev/null differ diff --git a/resources/ui/misc/original/money_icon.png b/resources/ui/misc/original/money_icon.png deleted file mode 100644 index ed217456f..000000000 Binary files a/resources/ui/misc/original/money_icon.png and /dev/null differ diff --git a/resources/ui/misc/original/new.png b/resources/ui/misc/original/new.png deleted file mode 100644 index 12131b010..000000000 Binary files a/resources/ui/misc/original/new.png and /dev/null differ diff --git a/resources/ui/misc/original/notes.png b/resources/ui/misc/original/notes.png deleted file mode 100644 index 1223307a4..000000000 Binary files a/resources/ui/misc/original/notes.png and /dev/null differ diff --git a/resources/ui/misc/original/open.png b/resources/ui/misc/original/open.png deleted file mode 100644 index 45fa2883a..000000000 Binary files a/resources/ui/misc/original/open.png and /dev/null differ diff --git a/resources/ui/misc/original/ordnance_icon.png b/resources/ui/misc/original/ordnance_icon.png deleted file mode 100644 index cf4674070..000000000 Binary files a/resources/ui/misc/original/ordnance_icon.png and /dev/null differ diff --git a/resources/ui/misc/original/proceed.png b/resources/ui/misc/original/proceed.png deleted file mode 100644 index 1908418d9..000000000 Binary files a/resources/ui/misc/original/proceed.png and /dev/null differ diff --git a/resources/ui/misc/original/save.png b/resources/ui/misc/original/save.png deleted file mode 100644 index daba865fa..000000000 Binary files a/resources/ui/misc/original/save.png and /dev/null differ diff --git a/resources/ui/misc/original/settings.png b/resources/ui/misc/original/settings.png deleted file mode 100644 index 3caf5ba31..000000000 Binary files a/resources/ui/misc/original/settings.png and /dev/null differ diff --git a/resources/ui/misc/original/statistics.png b/resources/ui/misc/original/statistics.png deleted file mode 100644 index fdbcee659..000000000 Binary files a/resources/ui/misc/original/statistics.png and /dev/null differ diff --git a/resources/ui/misc/proceed.png b/resources/ui/misc/proceed.png deleted file mode 100644 index 22c9b89dd..000000000 Binary files a/resources/ui/misc/proceed.png and /dev/null differ diff --git a/resources/ui/misc/red-sam.png b/resources/ui/misc/red-sam.png deleted file mode 100644 index bdfd28db8..000000000 Binary files a/resources/ui/misc/red-sam.png and /dev/null differ diff --git a/resources/ui/misc/save.png b/resources/ui/misc/save.png deleted file mode 100644 index 550b49633..000000000 Binary files a/resources/ui/misc/save.png and /dev/null differ diff --git a/resources/ui/misc/settings.png b/resources/ui/misc/settings.png deleted file mode 100644 index 058808b8f..000000000 Binary files a/resources/ui/misc/settings.png and /dev/null differ diff --git a/resources/ui/misc/statistics.png b/resources/ui/misc/statistics.png deleted file mode 100644 index 731c69c76..000000000 Binary files a/resources/ui/misc/statistics.png and /dev/null differ diff --git a/resources/ui/misc/ukraine.png b/resources/ui/misc/ukraine.png deleted file mode 100644 index 55b97e908..000000000 Binary files a/resources/ui/misc/ukraine.png and /dev/null differ diff --git a/resources/ui/splash_screen.png b/resources/ui/splash_screen.png deleted file mode 100644 index 1411b7a11..000000000 Binary files a/resources/ui/splash_screen.png and /dev/null differ diff --git a/resources/ui/tasks/cap.png b/resources/ui/tasks/cap.png deleted file mode 100644 index 6551c7378..000000000 Binary files a/resources/ui/tasks/cap.png and /dev/null differ diff --git a/resources/ui/tasks/cas.png b/resources/ui/tasks/cas.png deleted file mode 100644 index ae1c1b927..000000000 Binary files a/resources/ui/tasks/cas.png and /dev/null differ diff --git a/resources/ui/tasks/empty.png b/resources/ui/tasks/empty.png deleted file mode 100644 index b7ff2b232..000000000 Binary files a/resources/ui/tasks/empty.png and /dev/null differ diff --git a/resources/ui/tasks/sead.png b/resources/ui/tasks/sead.png deleted file mode 100644 index 06eb74721..000000000 Binary files a/resources/ui/tasks/sead.png and /dev/null differ diff --git a/resources/ui/templates/campaign_performance_template_EN.j2 b/resources/ui/templates/campaign_performance_template_EN.j2 deleted file mode 100644 index 637f9ca77..000000000 --- a/resources/ui/templates/campaign_performance_template_EN.j2 +++ /dev/null @@ -1,33 +0,0 @@ -{% if performance == 0 %} -
    -{% elif performance == 1 %} -
    -{% elif performance == 2 %} -
    -{% else %} -
    -{%endif %} - -Performance impact :  {{performance}}/3 - -{% if performance == 0 %} -

    -This scenario is rather performance friendly. -

    -{% elif performance == 1 %} -

    -This scenario requires a very good computer to run. -

    -{% elif performance == 2 %} -

    -This scenario is not performance friendly. The usage of the culling settings is recommended for most users. -

    -{% elif performance == 3 %} -

    -This theater is huge, and will generate very complex DCS missions with hundreds of units, pushing the limits of DCS engine. -An insanely powerful computer will be necessary to run it. -Usage of culling settings will probably be mandatory for decent FPS. -

    -{%endif %} - -
    \ No newline at end of file diff --git a/resources/ui/templates/campaign_performance_template_FR.j2 b/resources/ui/templates/campaign_performance_template_FR.j2 deleted file mode 100644 index 455d2648a..000000000 --- a/resources/ui/templates/campaign_performance_template_FR.j2 +++ /dev/null @@ -1,33 +0,0 @@ -{% if performance == 0 %} -
    -{% elif performance == 1 %} -
    -{% elif performance == 2 %} -
    -{% else %} -
    -{%endif %} - -Impact sur les performances :  {{performance}}/3 - -{% if performance == 0 %} -

    -Ce scénario est d'une taille limitée et pensé pour obtenir de bonnes performances en jeu. -

    -{% elif performance == 1 %} -

    -Ce scénario nécessite une machine puissante. -

    -{% elif performance == 2 %} -

    -Ce scénario n'est pas pensé pour la performance et requiert une machine très puissante. -L'usage des paramètres "culling" est recommandé pour la plupart des utilisateurs. -

    -{% elif performance == 3 %} -

    -Ce scénario est gigantesque, et générera des missions DCS d'une grande compléxité contenant des centaines/milliers d'unités. -Une machine extrêmement puissante est nécessaire, et l'utilisation des paramètres de "culling" sera obligatoire pour des performances décentes. -

    -{%endif %} - -
    \ No newline at end of file diff --git a/resources/ui/templates/campaigntemplate_EN.j2 b/resources/ui/templates/campaigntemplate_EN.j2 deleted file mode 100644 index a5b1a2d4b..000000000 --- a/resources/ui/templates/campaigntemplate_EN.j2 +++ /dev/null @@ -1,25 +0,0 @@ -

    Author(s): {{ campaign.authors }}

    - -{% if not campaign.version %} -

    This campaign was created for an unknown version -of DCS Liberation.

    -

    You can still attempt to play this campaign but there may be game breaking -bugs.

    -{% elif campaign.is_out_of_date %} -

    This campaign was created for an older version -of DCS Liberation.

    -

    You can still attempt to play this campaign but there may be game breaking -bugs.

    -{% elif campaign.is_from_future %} -

    This campaign was created for a newer version -of DCS Liberation.

    -

    You can still attempt to play this campaign but there may be game breaking -bugs.

    -{% else %} -

    This campaign is up to date.

    -{% endif %} - -

    Default factions:

    -

    {{campaign.recommended_player_faction.name}} VS  {{campaign.recommended_enemy_faction.name}}

    - -{{ campaign.description|safe }} \ No newline at end of file diff --git a/resources/ui/templates/campaigntemplate_FR.j2 b/resources/ui/templates/campaigntemplate_FR.j2 deleted file mode 100644 index ea6111e61..000000000 --- a/resources/ui/templates/campaigntemplate_FR.j2 +++ /dev/null @@ -1,7 +0,0 @@ -Auteur(s) : {{ campaign.authors }} - -Factions par défaut : - {{campaign.recommended_player_faction.name}} VS  {{campaign.recommended_enemy_faction.name}} -
    - -{{ campaign.description|safe }} diff --git a/resources/ui/templates/factiontemplate_EN.j2 b/resources/ui/templates/factiontemplate_EN.j2 deleted file mode 100644 index d19b7c68b..000000000 --- a/resources/ui/templates/factiontemplate_EN.j2 +++ /dev/null @@ -1,54 +0,0 @@ -{{ faction.description|safe }} -
    - -Author(s): {{ faction.authors }} -

    - - -Potential aircraft: -

    - The aircraft that will be present in the game are specified by the campaign. - Only aircraft in this list will be allowed, but not all aircraft in this - list will necessarily be available. -

    -

    - If the campaign you chose doesn't include the aircraft you want to fly, you - can mod the campaign by following the squadron section of the - - custom campaigns guide. -

    -
      -{% for aircraft in faction.aircrafts | sort(attribute="display_name") %} -
    • {{aircraft.display_name}}
    • -{% endfor %} -
    -
    - -Frontlines vehicles: -
      -{% for vehicle in faction.frontline_units | sort(attribute="display_name") %} -
    • -{{ vehicle.display_name }} -
    • -{% endfor %} -
    -
    - -Artillery units: -
      -{% for arty in faction.artillery_units | sort(attribute="display_name") %} -
    • -{{ arty.display_name }} -
    • -{% endfor %} -
    -
    - -Air defenses: -
      -{% for air_defense in faction.air_defenses | sort() %} -
    • {{air_defense}}
    • -{% endfor %} -
    -
    diff --git a/resources/ui/templates/factiontemplate_FR.j2 b/resources/ui/templates/factiontemplate_FR.j2 deleted file mode 100644 index 3e7627745..000000000 --- a/resources/ui/templates/factiontemplate_FR.j2 +++ /dev/null @@ -1,43 +0,0 @@ -{{ faction.description|safe }} -
    - -Auteur(s): {{ faction.authors }} -

    - - -Aéronefs disponibles : -
      -{% for aircraft in faction.aircrafts | sort(attribute="display_name") %} -
    • {{aircraft.display_name}}
    • -{% endfor %} -
    -
    - -Véhicules disponibles : -
      -{% for vehicle in faction.frontline_units | sort(attribute="display_name") %} -
    • -{{ vehicle.display_name }} -{%endif %} -
    • -{% endfor %} -
    -
    - -Pièces d'artillerie : -
      -{% for arty in faction.artillery_units | sort(attribute="display_name") %} -
    • -{{ arty.display_name }} -
    • -{% endfor %} -
    -
    - -Défense Sol-Air: -
      -{% for air_defense in faction.air_defenses | sort() %} -
    • {{air_defense}}
    • -{% endfor %} -
    -
    diff --git a/resources/ui/templates/mission_start_EN.j2 b/resources/ui/templates/mission_start_EN.j2 deleted file mode 100644 index 61e05fab8..000000000 --- a/resources/ui/templates/mission_start_EN.j2 +++ /dev/null @@ -1,52 +0,0 @@ -You are clear for takeoff - -

    - Some player flights may be delayed to start. For such flights, it will not be - possible to enter the cockpit until its mission start time, shown in the flight - information window. -

    - -

    - To reduce delays, schedule packages with player flights with an earlier TOT. - Note that if some flights within the package will take a long time to reach the - target, a player flight may still be delayed. -

    - -

    - To avoid delays entirely, use the "Never delay player flights" option in the - mission generation settings. Note that this will not adjust - the timing of your mission; this option only allows you to wait in the - cockpit. -

    - -

    - For more information, see the - mission planning documentation on our wiki. -

    - -

    Launching the mission:

    - -

    - Launch the liberation_nextturn mission as you normally would for - single- or multi-player. -

    - -

    - For advice on using a dedicated server to play DCS Liberation, see - the guide on our wiki. -

    - -

    Finishing

    - -

    Once you have played the mission, click on the \"Accept Results\" button.

    - -

    - If DCS Liberation does not detect mission end, use the manually submit button, - and choose the state.json file. -

    \ No newline at end of file diff --git a/resources/ui/units/aircrafts/banners/A-10A.jpg b/resources/ui/units/aircrafts/banners/A-10A.jpg deleted file mode 100644 index d64e52a67..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-10A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/A-10C.jpg b/resources/ui/units/aircrafts/banners/A-10C.jpg deleted file mode 100644 index a605d02b1..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-10C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/A-10C_2.jpg b/resources/ui/units/aircrafts/banners/A-10C_2.jpg deleted file mode 100644 index 5e3a57b19..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-10C_2.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/A-20G.jpg b/resources/ui/units/aircrafts/banners/A-20G.jpg deleted file mode 100644 index 1850c2d36..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-20G.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/A-4E-C.jpg b/resources/ui/units/aircrafts/banners/A-4E-C.jpg deleted file mode 100644 index 5a9d34c62..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-4E-C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/A-50.jpg b/resources/ui/units/aircrafts/banners/A-50.jpg deleted file mode 100644 index c3eeaa7b5..000000000 Binary files a/resources/ui/units/aircrafts/banners/A-50.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AH-1W.jpg b/resources/ui/units/aircrafts/banners/AH-1W.jpg deleted file mode 100644 index 90cbc7558..000000000 Binary files a/resources/ui/units/aircrafts/banners/AH-1W.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AH-64A.jpg b/resources/ui/units/aircrafts/banners/AH-64A.jpg deleted file mode 100644 index b7dc4b877..000000000 Binary files a/resources/ui/units/aircrafts/banners/AH-64A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AH-64D.jpg b/resources/ui/units/aircrafts/banners/AH-64D.jpg deleted file mode 100644 index 76879f3fa..000000000 Binary files a/resources/ui/units/aircrafts/banners/AH-64D.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AH-64D_BLK_II.jpg b/resources/ui/units/aircrafts/banners/AH-64D_BLK_II.jpg deleted file mode 100644 index 5886e7366..000000000 Binary files a/resources/ui/units/aircrafts/banners/AH-64D_BLK_II.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AJS37.jpg b/resources/ui/units/aircrafts/banners/AJS37.jpg deleted file mode 100644 index d3556b498..000000000 Binary files a/resources/ui/units/aircrafts/banners/AJS37.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/AV8BNA.jpg b/resources/ui/units/aircrafts/banners/AV8BNA.jpg deleted file mode 100644 index 57d3f5e9a..000000000 Binary files a/resources/ui/units/aircrafts/banners/AV8BNA.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/An-26B.jpg b/resources/ui/units/aircrafts/banners/An-26B.jpg deleted file mode 100644 index b3b9b96d1..000000000 Binary files a/resources/ui/units/aircrafts/banners/An-26B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/B-17G.jpg b/resources/ui/units/aircrafts/banners/B-17G.jpg deleted file mode 100644 index 4ec81b539..000000000 Binary files a/resources/ui/units/aircrafts/banners/B-17G.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/B-1B.jpg b/resources/ui/units/aircrafts/banners/B-1B.jpg deleted file mode 100644 index 9a8893706..000000000 Binary files a/resources/ui/units/aircrafts/banners/B-1B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/B-52H.jpg b/resources/ui/units/aircrafts/banners/B-52H.jpg deleted file mode 100644 index f9eb42324..000000000 Binary files a/resources/ui/units/aircrafts/banners/B-52H.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Bf-109K-4.jpg b/resources/ui/units/aircrafts/banners/Bf-109K-4.jpg deleted file mode 100644 index e1dd8e57e..000000000 Binary files a/resources/ui/units/aircrafts/banners/Bf-109K-4.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Bronco-OV-10A.jpg b/resources/ui/units/aircrafts/banners/Bronco-OV-10A.jpg deleted file mode 100644 index 3abece860..000000000 Binary files a/resources/ui/units/aircrafts/banners/Bronco-OV-10A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/C-101CC.jpg b/resources/ui/units/aircrafts/banners/C-101CC.jpg deleted file mode 100644 index f53094650..000000000 Binary files a/resources/ui/units/aircrafts/banners/C-101CC.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/C-130.jpg b/resources/ui/units/aircrafts/banners/C-130.jpg deleted file mode 100644 index 1de082c0f..000000000 Binary files a/resources/ui/units/aircrafts/banners/C-130.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/C-17A.jpg b/resources/ui/units/aircrafts/banners/C-17A.jpg deleted file mode 100644 index c64cdd5a9..000000000 Binary files a/resources/ui/units/aircrafts/banners/C-17A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/C-47.jpg b/resources/ui/units/aircrafts/banners/C-47.jpg deleted file mode 100644 index f4b7cefb8..000000000 Binary files a/resources/ui/units/aircrafts/banners/C-47.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/CH-47D.jpg b/resources/ui/units/aircrafts/banners/CH-47D.jpg deleted file mode 100644 index 4a8ff767e..000000000 Binary files a/resources/ui/units/aircrafts/banners/CH-47D.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/CH-53E.jpg b/resources/ui/units/aircrafts/banners/CH-53E.jpg deleted file mode 100644 index 6bc73a196..000000000 Binary files a/resources/ui/units/aircrafts/banners/CH-53E.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/E-2C.jpg b/resources/ui/units/aircrafts/banners/E-2C.jpg deleted file mode 100644 index bf8e8073d..000000000 Binary files a/resources/ui/units/aircrafts/banners/E-2C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/E-3A.jpg b/resources/ui/units/aircrafts/banners/E-3A.jpg deleted file mode 100644 index 581f368b5..000000000 Binary files a/resources/ui/units/aircrafts/banners/E-3A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/EA-18G.jpg b/resources/ui/units/aircrafts/banners/EA-18G.jpg deleted file mode 100644 index 7d5ff0400..000000000 Binary files a/resources/ui/units/aircrafts/banners/EA-18G.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-117A.jpg b/resources/ui/units/aircrafts/banners/F-117A.jpg deleted file mode 100644 index ae16570d0..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-117A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-14A-135-GR.jpg b/resources/ui/units/aircrafts/banners/F-14A-135-GR.jpg deleted file mode 100644 index 3dc949bb2..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-14A-135-GR.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-14B.jpg b/resources/ui/units/aircrafts/banners/F-14B.jpg deleted file mode 100644 index be515b1f5..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-14B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-15C.jpg b/resources/ui/units/aircrafts/banners/F-15C.jpg deleted file mode 100644 index b87d8e154..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-15C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-15E.jpg b/resources/ui/units/aircrafts/banners/F-15E.jpg deleted file mode 100644 index 53d8b75c6..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-15E.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-16A.jpg b/resources/ui/units/aircrafts/banners/F-16A.jpg deleted file mode 100644 index 5eeb6160d..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-16A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-16C_50.jpg b/resources/ui/units/aircrafts/banners/F-16C_50.jpg deleted file mode 100644 index 13b0ce192..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-16C_50.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-22A.jpg b/resources/ui/units/aircrafts/banners/F-22A.jpg deleted file mode 100644 index 15d6071a0..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-22A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-4E.jpg b/resources/ui/units/aircrafts/banners/F-4E.jpg deleted file mode 100644 index a880fcdcf..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-4E.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-5E-3.jpg b/resources/ui/units/aircrafts/banners/F-5E-3.jpg deleted file mode 100644 index 75985e551..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-5E-3.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/F-86F Sabre.jpg b/resources/ui/units/aircrafts/banners/F-86F Sabre.jpg deleted file mode 100644 index 1fdd30bd8..000000000 Binary files a/resources/ui/units/aircrafts/banners/F-86F Sabre.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/FA-18C_hornet.jpg b/resources/ui/units/aircrafts/banners/FA-18C_hornet.jpg deleted file mode 100644 index 68e758a30..000000000 Binary files a/resources/ui/units/aircrafts/banners/FA-18C_hornet.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/FA-18E.jpg b/resources/ui/units/aircrafts/banners/FA-18E.jpg deleted file mode 100644 index ecd029eb5..000000000 Binary files a/resources/ui/units/aircrafts/banners/FA-18E.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/FA-18F.jpg b/resources/ui/units/aircrafts/banners/FA-18F.jpg deleted file mode 100644 index 470472b0e..000000000 Binary files a/resources/ui/units/aircrafts/banners/FA-18F.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/FW-190A8.jpg b/resources/ui/units/aircrafts/banners/FW-190A8.jpg deleted file mode 100644 index e4ccec088..000000000 Binary files a/resources/ui/units/aircrafts/banners/FW-190A8.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/FW-190D9.jpg b/resources/ui/units/aircrafts/banners/FW-190D9.jpg deleted file mode 100644 index 9265398c5..000000000 Binary files a/resources/ui/units/aircrafts/banners/FW-190D9.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/H-6J.jpg b/resources/ui/units/aircrafts/banners/H-6J.jpg deleted file mode 100644 index 7755633f9..000000000 Binary files a/resources/ui/units/aircrafts/banners/H-6J.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/I-16.jpg b/resources/ui/units/aircrafts/banners/I-16.jpg deleted file mode 100644 index a55b31b18..000000000 Binary files a/resources/ui/units/aircrafts/banners/I-16.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/IL-76MD.jpg b/resources/ui/units/aircrafts/banners/IL-76MD.jpg deleted file mode 100644 index eb705f025..000000000 Binary files a/resources/ui/units/aircrafts/banners/IL-76MD.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/IL-78M.jpg b/resources/ui/units/aircrafts/banners/IL-78M.jpg deleted file mode 100644 index e7f4e030e..000000000 Binary files a/resources/ui/units/aircrafts/banners/IL-78M.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/J-11A.jpg b/resources/ui/units/aircrafts/banners/J-11A.jpg deleted file mode 100644 index 6625129c3..000000000 Binary files a/resources/ui/units/aircrafts/banners/J-11A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/JAS39Gripen.jpg b/resources/ui/units/aircrafts/banners/JAS39Gripen.jpg deleted file mode 100644 index 3d58c569e..000000000 Binary files a/resources/ui/units/aircrafts/banners/JAS39Gripen.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/JAS39Gripen_AG.jpg b/resources/ui/units/aircrafts/banners/JAS39Gripen_AG.jpg deleted file mode 100644 index 403f2fe89..000000000 Binary files a/resources/ui/units/aircrafts/banners/JAS39Gripen_AG.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/JF-17.jpg b/resources/ui/units/aircrafts/banners/JF-17.jpg deleted file mode 100644 index 1359ddb38..000000000 Binary files a/resources/ui/units/aircrafts/banners/JF-17.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Ju-88A4.jpg b/resources/ui/units/aircrafts/banners/Ju-88A4.jpg deleted file mode 100644 index 00fe95a7e..000000000 Binary files a/resources/ui/units/aircrafts/banners/Ju-88A4.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/KC-135.jpg b/resources/ui/units/aircrafts/banners/KC-135.jpg deleted file mode 100644 index a466c91a4..000000000 Binary files a/resources/ui/units/aircrafts/banners/KC-135.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/KC130.jpg b/resources/ui/units/aircrafts/banners/KC130.jpg deleted file mode 100644 index fdb76af57..000000000 Binary files a/resources/ui/units/aircrafts/banners/KC130.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/KC130J.jpg b/resources/ui/units/aircrafts/banners/KC130J.jpg deleted file mode 100644 index 71d2197c6..000000000 Binary files a/resources/ui/units/aircrafts/banners/KC130J.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/KJ-2000.jpg b/resources/ui/units/aircrafts/banners/KJ-2000.jpg deleted file mode 100644 index 01ed613a0..000000000 Binary files a/resources/ui/units/aircrafts/banners/KJ-2000.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Ka-50.jpg b/resources/ui/units/aircrafts/banners/Ka-50.jpg deleted file mode 100644 index 94fee740b..000000000 Binary files a/resources/ui/units/aircrafts/banners/Ka-50.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Ka-50_3.jpg b/resources/ui/units/aircrafts/banners/Ka-50_3.jpg deleted file mode 100644 index 94fee740b..000000000 Binary files a/resources/ui/units/aircrafts/banners/Ka-50_3.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/L-39ZA.jpg b/resources/ui/units/aircrafts/banners/L-39ZA.jpg deleted file mode 100644 index 605acb55d..000000000 Binary files a/resources/ui/units/aircrafts/banners/L-39ZA.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/M-2000C.jpg b/resources/ui/units/aircrafts/banners/M-2000C.jpg deleted file mode 100644 index e380badc8..000000000 Binary files a/resources/ui/units/aircrafts/banners/M-2000C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MB-339A.jpg b/resources/ui/units/aircrafts/banners/MB-339A.jpg deleted file mode 100644 index 29cd761c2..000000000 Binary files a/resources/ui/units/aircrafts/banners/MB-339A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MI-26.jpg b/resources/ui/units/aircrafts/banners/MI-26.jpg deleted file mode 100644 index 7e710d5b7..000000000 Binary files a/resources/ui/units/aircrafts/banners/MI-26.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MIG-25RBT.jpg b/resources/ui/units/aircrafts/banners/MIG-25RBT.jpg deleted file mode 100644 index 174857e2f..000000000 Binary files a/resources/ui/units/aircrafts/banners/MIG-25RBT.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mi-24P.jpg b/resources/ui/units/aircrafts/banners/Mi-24P.jpg deleted file mode 100644 index fd912f70a..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mi-24P.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mi-24V.jpg b/resources/ui/units/aircrafts/banners/Mi-24V.jpg deleted file mode 100644 index 14b5dca15..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mi-24V.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mi-28N.jpg b/resources/ui/units/aircrafts/banners/Mi-28N.jpg deleted file mode 100644 index 30d57738b..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mi-28N.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mi-8MT.jpg b/resources/ui/units/aircrafts/banners/Mi-8MT.jpg deleted file mode 100644 index 199c3241d..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mi-8MT.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-15bis.jpg b/resources/ui/units/aircrafts/banners/MiG-15bis.jpg deleted file mode 100644 index 541a30e47..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-15bis.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-19P.jpg b/resources/ui/units/aircrafts/banners/MiG-19P.jpg deleted file mode 100644 index 4078f8cc9..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-19P.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-21Bis.jpg b/resources/ui/units/aircrafts/banners/MiG-21Bis.jpg deleted file mode 100644 index dc7ffce66..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-21Bis.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-23MLD.jpg b/resources/ui/units/aircrafts/banners/MiG-23MLD.jpg deleted file mode 100644 index 212393f45..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-23MLD.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-25PD.jpg b/resources/ui/units/aircrafts/banners/MiG-25PD.jpg deleted file mode 100644 index 67fb469a5..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-25PD.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-27K.jpg b/resources/ui/units/aircrafts/banners/MiG-27K.jpg deleted file mode 100644 index 25312ccdd..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-27K.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-29A.jpg b/resources/ui/units/aircrafts/banners/MiG-29A.jpg deleted file mode 100644 index bac81243c..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-29A.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-29G.jpg b/resources/ui/units/aircrafts/banners/MiG-29G.jpg deleted file mode 100644 index 13dc90100..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-29G.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-29S.jpg b/resources/ui/units/aircrafts/banners/MiG-29S.jpg deleted file mode 100644 index 0be534f6d..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-29S.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MiG-31.jpg b/resources/ui/units/aircrafts/banners/MiG-31.jpg deleted file mode 100644 index 0ce90765a..000000000 Binary files a/resources/ui/units/aircrafts/banners/MiG-31.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mirage 2000-5.jpg b/resources/ui/units/aircrafts/banners/Mirage 2000-5.jpg deleted file mode 100644 index 82d5a828d..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mirage 2000-5.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mirage-F1B.jpg b/resources/ui/units/aircrafts/banners/Mirage-F1B.jpg deleted file mode 100644 index 0478d0aa8..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mirage-F1B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mirage-F1BE.jpg b/resources/ui/units/aircrafts/banners/Mirage-F1BE.jpg deleted file mode 100644 index 90a2abd87..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mirage-F1BE.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mirage-F1C-200.jpg b/resources/ui/units/aircrafts/banners/Mirage-F1C-200.jpg deleted file mode 100644 index 605cdd005..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mirage-F1C-200.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Mirage-F1C.jpg b/resources/ui/units/aircrafts/banners/Mirage-F1C.jpg deleted file mode 100644 index d8cb87874..000000000 Binary files a/resources/ui/units/aircrafts/banners/Mirage-F1C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Missing.jpg b/resources/ui/units/aircrafts/banners/Missing.jpg deleted file mode 100644 index b965ab5b5..000000000 Binary files a/resources/ui/units/aircrafts/banners/Missing.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/MosquitoFBMkVI.jpg b/resources/ui/units/aircrafts/banners/MosquitoFBMkVI.jpg deleted file mode 100644 index eee8d4c02..000000000 Binary files a/resources/ui/units/aircrafts/banners/MosquitoFBMkVI.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/OH-58D.jpg b/resources/ui/units/aircrafts/banners/OH-58D.jpg deleted file mode 100644 index b81d698bf..000000000 Binary files a/resources/ui/units/aircrafts/banners/OH-58D.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/P-47D-30.jpg b/resources/ui/units/aircrafts/banners/P-47D-30.jpg deleted file mode 100644 index a5486de02..000000000 Binary files a/resources/ui/units/aircrafts/banners/P-47D-30.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/P-47D-30bl1.jpg b/resources/ui/units/aircrafts/banners/P-47D-30bl1.jpg deleted file mode 100644 index 08a12287e..000000000 Binary files a/resources/ui/units/aircrafts/banners/P-47D-30bl1.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/P-47D-40.jpg b/resources/ui/units/aircrafts/banners/P-47D-40.jpg deleted file mode 100644 index 1591a6581..000000000 Binary files a/resources/ui/units/aircrafts/banners/P-47D-40.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/P-51D-30-NA.jpg b/resources/ui/units/aircrafts/banners/P-51D-30-NA.jpg deleted file mode 100644 index c1bc72ac5..000000000 Binary files a/resources/ui/units/aircrafts/banners/P-51D-30-NA.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/P-51D.jpg b/resources/ui/units/aircrafts/banners/P-51D.jpg deleted file mode 100644 index cbbba314f..000000000 Binary files a/resources/ui/units/aircrafts/banners/P-51D.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/S-3B Tanker.jpg b/resources/ui/units/aircrafts/banners/S-3B Tanker.jpg deleted file mode 100644 index 146f012df..000000000 Binary files a/resources/ui/units/aircrafts/banners/S-3B Tanker.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/S-3B.jpg b/resources/ui/units/aircrafts/banners/S-3B.jpg deleted file mode 100644 index bd96ab36e..000000000 Binary files a/resources/ui/units/aircrafts/banners/S-3B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SA342L.jpg b/resources/ui/units/aircrafts/banners/SA342L.jpg deleted file mode 100644 index da94a7f67..000000000 Binary files a/resources/ui/units/aircrafts/banners/SA342L.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SA342M.jpg b/resources/ui/units/aircrafts/banners/SA342M.jpg deleted file mode 100644 index 20cc99b42..000000000 Binary files a/resources/ui/units/aircrafts/banners/SA342M.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SA342Mistral.jpg b/resources/ui/units/aircrafts/banners/SA342Mistral.jpg deleted file mode 100644 index 97b353cf2..000000000 Binary files a/resources/ui/units/aircrafts/banners/SA342Mistral.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SH-60B.jpg b/resources/ui/units/aircrafts/banners/SH-60B.jpg deleted file mode 100644 index d661aeefe..000000000 Binary files a/resources/ui/units/aircrafts/banners/SH-60B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SU-24MR.jpg b/resources/ui/units/aircrafts/banners/SU-24MR.jpg deleted file mode 100644 index c585c3be0..000000000 Binary files a/resources/ui/units/aircrafts/banners/SU-24MR.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SpitfireLFMkIX.jpg b/resources/ui/units/aircrafts/banners/SpitfireLFMkIX.jpg deleted file mode 100644 index 03a44f9e4..000000000 Binary files a/resources/ui/units/aircrafts/banners/SpitfireLFMkIX.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/SpitfireLFMkIXCW.jpg b/resources/ui/units/aircrafts/banners/SpitfireLFMkIXCW.jpg deleted file mode 100644 index aee809d49..000000000 Binary files a/resources/ui/units/aircrafts/banners/SpitfireLFMkIXCW.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-17M4.jpg b/resources/ui/units/aircrafts/banners/Su-17M4.jpg deleted file mode 100644 index ded8d32f8..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-17M4.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-24M.jpg b/resources/ui/units/aircrafts/banners/Su-24M.jpg deleted file mode 100644 index 9952c949f..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-24M.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-25T_25.jpg b/resources/ui/units/aircrafts/banners/Su-25T_25.jpg deleted file mode 100644 index fc7831539..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-25T_25.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-25_25.jpg b/resources/ui/units/aircrafts/banners/Su-25_25.jpg deleted file mode 100644 index 249ab7e6d..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-25_25.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-27.jpg b/resources/ui/units/aircrafts/banners/Su-27.jpg deleted file mode 100644 index 751af137d..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-27.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-30.jpg b/resources/ui/units/aircrafts/banners/Su-30.jpg deleted file mode 100644 index 9441d321f..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-30.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-33.jpg b/resources/ui/units/aircrafts/banners/Su-33.jpg deleted file mode 100644 index fb098ec98..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-33.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Su-34.jpg b/resources/ui/units/aircrafts/banners/Su-34.jpg deleted file mode 100644 index 60bc9704a..000000000 Binary files a/resources/ui/units/aircrafts/banners/Su-34.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tornado GR4.jpg b/resources/ui/units/aircrafts/banners/Tornado GR4.jpg deleted file mode 100644 index 01ac443d6..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tornado GR4.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tornado IDS.jpg b/resources/ui/units/aircrafts/banners/Tornado IDS.jpg deleted file mode 100644 index 38ba26f6a..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tornado IDS.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tu-142.jpg b/resources/ui/units/aircrafts/banners/Tu-142.jpg deleted file mode 100644 index 3b7b87d19..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tu-142.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tu-160.jpg b/resources/ui/units/aircrafts/banners/Tu-160.jpg deleted file mode 100644 index f8ceea422..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tu-160.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tu-22M3.jpg b/resources/ui/units/aircrafts/banners/Tu-22M3.jpg deleted file mode 100644 index d947877a3..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tu-22M3.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/Tu-95MS.jpg b/resources/ui/units/aircrafts/banners/Tu-95MS.jpg deleted file mode 100644 index 39230aed9..000000000 Binary files a/resources/ui/units/aircrafts/banners/Tu-95MS.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/UH-1H.jpg b/resources/ui/units/aircrafts/banners/UH-1H.jpg deleted file mode 100644 index 0b3508a75..000000000 Binary files a/resources/ui/units/aircrafts/banners/UH-1H.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/UH-60L.jpg b/resources/ui/units/aircrafts/banners/UH-60L.jpg deleted file mode 100644 index 4b5694430..000000000 Binary files a/resources/ui/units/aircrafts/banners/UH-60L.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/VSN_F104G.jpg b/resources/ui/units/aircrafts/banners/VSN_F104G.jpg deleted file mode 100644 index 679fe6e98..000000000 Binary files a/resources/ui/units/aircrafts/banners/VSN_F104G.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/VSN_F104S.jpg b/resources/ui/units/aircrafts/banners/VSN_F104S.jpg deleted file mode 100644 index 7fcb9a9f7..000000000 Binary files a/resources/ui/units/aircrafts/banners/VSN_F104S.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/VSN_F104S_AG.jpg b/resources/ui/units/aircrafts/banners/VSN_F104S_AG.jpg deleted file mode 100644 index 7fcb9a9f7..000000000 Binary files a/resources/ui/units/aircrafts/banners/VSN_F104S_AG.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/VSN_F4B.jpg b/resources/ui/units/aircrafts/banners/VSN_F4B.jpg deleted file mode 100644 index d091d96dc..000000000 Binary files a/resources/ui/units/aircrafts/banners/VSN_F4B.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/banners/VSN_F4C.jpg b/resources/ui/units/aircrafts/banners/VSN_F4C.jpg deleted file mode 100644 index 2ab7473d8..000000000 Binary files a/resources/ui/units/aircrafts/banners/VSN_F4C.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/A-10A_24.jpg b/resources/ui/units/aircrafts/icons/A-10A_24.jpg deleted file mode 100644 index 0c5ae4477..000000000 Binary files a/resources/ui/units/aircrafts/icons/A-10A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/A-10C_24.jpg b/resources/ui/units/aircrafts/icons/A-10C_24.jpg deleted file mode 100644 index 433b0f451..000000000 Binary files a/resources/ui/units/aircrafts/icons/A-10C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/A-20G_24.jpg b/resources/ui/units/aircrafts/icons/A-20G_24.jpg deleted file mode 100644 index a0e0e35b1..000000000 Binary files a/resources/ui/units/aircrafts/icons/A-20G_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/A-4E-C_24.jpg b/resources/ui/units/aircrafts/icons/A-4E-C_24.jpg deleted file mode 100644 index 4a00e3835..000000000 Binary files a/resources/ui/units/aircrafts/icons/A-4E-C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/A-50_24.jpg b/resources/ui/units/aircrafts/icons/A-50_24.jpg deleted file mode 100644 index c79c68361..000000000 Binary files a/resources/ui/units/aircrafts/icons/A-50_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AH-1W_24.jpg b/resources/ui/units/aircrafts/icons/AH-1W_24.jpg deleted file mode 100644 index cbab793f0..000000000 Binary files a/resources/ui/units/aircrafts/icons/AH-1W_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AH-64A_24.jpg b/resources/ui/units/aircrafts/icons/AH-64A_24.jpg deleted file mode 100644 index 65ad0301e..000000000 Binary files a/resources/ui/units/aircrafts/icons/AH-64A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AH-64D_24.jpg b/resources/ui/units/aircrafts/icons/AH-64D_24.jpg deleted file mode 100644 index cbc1ff42e..000000000 Binary files a/resources/ui/units/aircrafts/icons/AH-64D_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AH-64D_BLK_II_24.jpg b/resources/ui/units/aircrafts/icons/AH-64D_BLK_II_24.jpg deleted file mode 100644 index cbc1ff42e..000000000 Binary files a/resources/ui/units/aircrafts/icons/AH-64D_BLK_II_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AJS37_24.jpg b/resources/ui/units/aircrafts/icons/AJS37_24.jpg deleted file mode 100644 index a973d5a20..000000000 Binary files a/resources/ui/units/aircrafts/icons/AJS37_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/AV8BNA_24.jpg b/resources/ui/units/aircrafts/icons/AV8BNA_24.jpg deleted file mode 100644 index b688a886a..000000000 Binary files a/resources/ui/units/aircrafts/icons/AV8BNA_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/An-26B_24.jpg b/resources/ui/units/aircrafts/icons/An-26B_24.jpg deleted file mode 100644 index 8d6bc5731..000000000 Binary files a/resources/ui/units/aircrafts/icons/An-26B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/An-30M_24.jpg b/resources/ui/units/aircrafts/icons/An-30M_24.jpg deleted file mode 100644 index e532aefa7..000000000 Binary files a/resources/ui/units/aircrafts/icons/An-30M_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/B-17G_24.jpg b/resources/ui/units/aircrafts/icons/B-17G_24.jpg deleted file mode 100644 index 8f0c23ed7..000000000 Binary files a/resources/ui/units/aircrafts/icons/B-17G_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/B-1B_24.jpg b/resources/ui/units/aircrafts/icons/B-1B_24.jpg deleted file mode 100644 index 1e9603aa8..000000000 Binary files a/resources/ui/units/aircrafts/icons/B-1B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/B-52H_24.jpg b/resources/ui/units/aircrafts/icons/B-52H_24.jpg deleted file mode 100644 index 0db4c82cb..000000000 Binary files a/resources/ui/units/aircrafts/icons/B-52H_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Bf-109K-4_24.jpg b/resources/ui/units/aircrafts/icons/Bf-109K-4_24.jpg deleted file mode 100644 index f024fabb1..000000000 Binary files a/resources/ui/units/aircrafts/icons/Bf-109K-4_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Bronco-OV-10A_24.jpg b/resources/ui/units/aircrafts/icons/Bronco-OV-10A_24.jpg deleted file mode 100644 index 2407cf514..000000000 Binary files a/resources/ui/units/aircrafts/icons/Bronco-OV-10A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/C-101CC_24.jpg b/resources/ui/units/aircrafts/icons/C-101CC_24.jpg deleted file mode 100644 index 22f59644f..000000000 Binary files a/resources/ui/units/aircrafts/icons/C-101CC_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/C-130_24.jpg b/resources/ui/units/aircrafts/icons/C-130_24.jpg deleted file mode 100644 index b970e7981..000000000 Binary files a/resources/ui/units/aircrafts/icons/C-130_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/C-17A_24.jpg b/resources/ui/units/aircrafts/icons/C-17A_24.jpg deleted file mode 100644 index 1832989e2..000000000 Binary files a/resources/ui/units/aircrafts/icons/C-17A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/C-47_24.jpg b/resources/ui/units/aircrafts/icons/C-47_24.jpg deleted file mode 100644 index 3e49ef05c..000000000 Binary files a/resources/ui/units/aircrafts/icons/C-47_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/CH-47D_24.jpg b/resources/ui/units/aircrafts/icons/CH-47D_24.jpg deleted file mode 100644 index 48647792a..000000000 Binary files a/resources/ui/units/aircrafts/icons/CH-47D_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/CH-53E_24.jpg b/resources/ui/units/aircrafts/icons/CH-53E_24.jpg deleted file mode 100644 index 3191ffaab..000000000 Binary files a/resources/ui/units/aircrafts/icons/CH-53E_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Christen Eagle II_24.jpg b/resources/ui/units/aircrafts/icons/Christen Eagle II_24.jpg deleted file mode 100644 index 50f875978..000000000 Binary files a/resources/ui/units/aircrafts/icons/Christen Eagle II_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/E-2C_24.jpg b/resources/ui/units/aircrafts/icons/E-2C_24.jpg deleted file mode 100644 index 9cf5dd657..000000000 Binary files a/resources/ui/units/aircrafts/icons/E-2C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/E-2D_24.jpg b/resources/ui/units/aircrafts/icons/E-2D_24.jpg deleted file mode 100644 index 9cf5dd657..000000000 Binary files a/resources/ui/units/aircrafts/icons/E-2D_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/E-3A_24.jpg b/resources/ui/units/aircrafts/icons/E-3A_24.jpg deleted file mode 100644 index 07675cfc0..000000000 Binary files a/resources/ui/units/aircrafts/icons/E-3A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/E-3C_24.jpg b/resources/ui/units/aircrafts/icons/E-3C_24.jpg deleted file mode 100644 index b1df7a9f0..000000000 Binary files a/resources/ui/units/aircrafts/icons/E-3C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/EA-18G_24.jpg b/resources/ui/units/aircrafts/icons/EA-18G_24.jpg deleted file mode 100644 index d960bbaaa..000000000 Binary files a/resources/ui/units/aircrafts/icons/EA-18G_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-117A_24.jpg b/resources/ui/units/aircrafts/icons/F-117A_24.jpg deleted file mode 100644 index 13b9f5be7..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-117A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-14A-135-GR_24.jpg b/resources/ui/units/aircrafts/icons/F-14A-135-GR_24.jpg deleted file mode 100644 index 6ff978cb3..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-14A-135-GR_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-14A_24.jpg b/resources/ui/units/aircrafts/icons/F-14A_24.jpg deleted file mode 100644 index 6ff978cb3..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-14A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-14B_24.jpg b/resources/ui/units/aircrafts/icons/F-14B_24.jpg deleted file mode 100644 index b6d90a237..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-14B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-15C_24.jpg b/resources/ui/units/aircrafts/icons/F-15C_24.jpg deleted file mode 100644 index 33298e466..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-15C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-15E_24.jpg b/resources/ui/units/aircrafts/icons/F-15E_24.jpg deleted file mode 100644 index 2f1f5154c..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-15E_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-16A_24.jpg b/resources/ui/units/aircrafts/icons/F-16A_24.jpg deleted file mode 100644 index 75ae23867..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-16A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-16C_24.jpg b/resources/ui/units/aircrafts/icons/F-16C_24.jpg deleted file mode 100644 index 96d6deace..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-16C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-22A_24.jpg b/resources/ui/units/aircrafts/icons/F-22A_24.jpg deleted file mode 100644 index 22df550a0..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-22A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-4E_24.jpg b/resources/ui/units/aircrafts/icons/F-4E_24.jpg deleted file mode 100644 index 231566fb4..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-4E_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-5E-3_24.jpg b/resources/ui/units/aircrafts/icons/F-5E-3_24.jpg deleted file mode 100644 index 244100e94..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-5E-3_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/F-86F Sabre_24.jpg b/resources/ui/units/aircrafts/icons/F-86F Sabre_24.jpg deleted file mode 100644 index 9a1cd52f4..000000000 Binary files a/resources/ui/units/aircrafts/icons/F-86F Sabre_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/FA-18C_24.jpg b/resources/ui/units/aircrafts/icons/FA-18C_24.jpg deleted file mode 100644 index e20a2fc8a..000000000 Binary files a/resources/ui/units/aircrafts/icons/FA-18C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/FA-18E_24.jpg b/resources/ui/units/aircrafts/icons/FA-18E_24.jpg deleted file mode 100644 index 993bc9d8d..000000000 Binary files a/resources/ui/units/aircrafts/icons/FA-18E_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/FA-18F_24.jpg b/resources/ui/units/aircrafts/icons/FA-18F_24.jpg deleted file mode 100644 index 218b1db18..000000000 Binary files a/resources/ui/units/aircrafts/icons/FA-18F_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/FW-190A8_24.jpg b/resources/ui/units/aircrafts/icons/FW-190A8_24.jpg deleted file mode 100644 index 688959606..000000000 Binary files a/resources/ui/units/aircrafts/icons/FW-190A8_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/FW-190D9_24.jpg b/resources/ui/units/aircrafts/icons/FW-190D9_24.jpg deleted file mode 100644 index af7c52c45..000000000 Binary files a/resources/ui/units/aircrafts/icons/FW-190D9_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/H-6J_24.jpg b/resources/ui/units/aircrafts/icons/H-6J_24.jpg deleted file mode 100644 index 79214314a..000000000 Binary files a/resources/ui/units/aircrafts/icons/H-6J_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Hawk T.1A_24.jpg b/resources/ui/units/aircrafts/icons/Hawk T.1A_24.jpg deleted file mode 100644 index cba6259fb..000000000 Binary files a/resources/ui/units/aircrafts/icons/Hawk T.1A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/I-16_24.jpg b/resources/ui/units/aircrafts/icons/I-16_24.jpg deleted file mode 100644 index 118c699f5..000000000 Binary files a/resources/ui/units/aircrafts/icons/I-16_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/IL-76MD_24.jpg b/resources/ui/units/aircrafts/icons/IL-76MD_24.jpg deleted file mode 100644 index a25bad96c..000000000 Binary files a/resources/ui/units/aircrafts/icons/IL-76MD_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/IL-78M_24.jpg b/resources/ui/units/aircrafts/icons/IL-78M_24.jpg deleted file mode 100644 index a27276e11..000000000 Binary files a/resources/ui/units/aircrafts/icons/IL-78M_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/J-11A_24.jpg b/resources/ui/units/aircrafts/icons/J-11A_24.jpg deleted file mode 100644 index 6d0934a01..000000000 Binary files a/resources/ui/units/aircrafts/icons/J-11A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/JAS39Gripen_24.jpg b/resources/ui/units/aircrafts/icons/JAS39Gripen_24.jpg deleted file mode 100644 index 0a5315783..000000000 Binary files a/resources/ui/units/aircrafts/icons/JAS39Gripen_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/JAS39Gripen_AG_24.jpg b/resources/ui/units/aircrafts/icons/JAS39Gripen_AG_24.jpg deleted file mode 100644 index 0a5315783..000000000 Binary files a/resources/ui/units/aircrafts/icons/JAS39Gripen_AG_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/JF-17_24.jpg b/resources/ui/units/aircrafts/icons/JF-17_24.jpg deleted file mode 100644 index e336ddd58..000000000 Binary files a/resources/ui/units/aircrafts/icons/JF-17_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Ju-88A4_24.jpg b/resources/ui/units/aircrafts/icons/Ju-88A4_24.jpg deleted file mode 100644 index def4dc792..000000000 Binary files a/resources/ui/units/aircrafts/icons/Ju-88A4_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/KC-135_24.jpg b/resources/ui/units/aircrafts/icons/KC-135_24.jpg deleted file mode 100644 index 118a0a836..000000000 Binary files a/resources/ui/units/aircrafts/icons/KC-135_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/KC130J_24.jpg b/resources/ui/units/aircrafts/icons/KC130J_24.jpg deleted file mode 100644 index 95301f5ad..000000000 Binary files a/resources/ui/units/aircrafts/icons/KC130J_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/KC130_24.jpg b/resources/ui/units/aircrafts/icons/KC130_24.jpg deleted file mode 100644 index 95301f5ad..000000000 Binary files a/resources/ui/units/aircrafts/icons/KC130_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/KC135MPRS_24.jpg b/resources/ui/units/aircrafts/icons/KC135MPRS_24.jpg deleted file mode 100644 index 18016ca21..000000000 Binary files a/resources/ui/units/aircrafts/icons/KC135MPRS_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/KJ-2000_24.jpg b/resources/ui/units/aircrafts/icons/KJ-2000_24.jpg deleted file mode 100644 index 23c8a011b..000000000 Binary files a/resources/ui/units/aircrafts/icons/KJ-2000_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Ka-27_24.jpg b/resources/ui/units/aircrafts/icons/Ka-27_24.jpg deleted file mode 100644 index 16baf14a8..000000000 Binary files a/resources/ui/units/aircrafts/icons/Ka-27_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Ka-50_24.jpg b/resources/ui/units/aircrafts/icons/Ka-50_24.jpg deleted file mode 100644 index 214e487ed..000000000 Binary files a/resources/ui/units/aircrafts/icons/Ka-50_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Ka-50_3_24.jpg b/resources/ui/units/aircrafts/icons/Ka-50_3_24.jpg deleted file mode 100644 index 214e487ed..000000000 Binary files a/resources/ui/units/aircrafts/icons/Ka-50_3_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/L-39C_24.jpg b/resources/ui/units/aircrafts/icons/L-39C_24.jpg deleted file mode 100644 index ffff344b8..000000000 Binary files a/resources/ui/units/aircrafts/icons/L-39C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/L-39ZA_24.jpg b/resources/ui/units/aircrafts/icons/L-39ZA_24.jpg deleted file mode 100644 index 6658aa4d0..000000000 Binary files a/resources/ui/units/aircrafts/icons/L-39ZA_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/M-2000C_24.jpg b/resources/ui/units/aircrafts/icons/M-2000C_24.jpg deleted file mode 100644 index f3f4bae73..000000000 Binary files a/resources/ui/units/aircrafts/icons/M-2000C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MB-339A PAN_24.jpg b/resources/ui/units/aircrafts/icons/MB-339A PAN_24.jpg deleted file mode 100644 index 60f5ae4d8..000000000 Binary files a/resources/ui/units/aircrafts/icons/MB-339A PAN_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MB-339PAN_24.jpg b/resources/ui/units/aircrafts/icons/MB-339PAN_24.jpg deleted file mode 100644 index c4dfd7092..000000000 Binary files a/resources/ui/units/aircrafts/icons/MB-339PAN_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MQ RQ-1_24.jpg b/resources/ui/units/aircrafts/icons/MQ RQ-1_24.jpg deleted file mode 100644 index 732d3f69d..000000000 Binary files a/resources/ui/units/aircrafts/icons/MQ RQ-1_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MQ-1A Predator_24.jpg b/resources/ui/units/aircrafts/icons/MQ-1A Predator_24.jpg deleted file mode 100644 index f953e2ac3..000000000 Binary files a/resources/ui/units/aircrafts/icons/MQ-1A Predator_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MQ-9 Reaper_24.jpg b/resources/ui/units/aircrafts/icons/MQ-9 Reaper_24.jpg deleted file mode 100644 index d49ef6d78..000000000 Binary files a/resources/ui/units/aircrafts/icons/MQ-9 Reaper_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mi-24P_24.jpg b/resources/ui/units/aircrafts/icons/Mi-24P_24.jpg deleted file mode 100644 index 97efd5185..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mi-24P_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mi-24V_24.jpg b/resources/ui/units/aircrafts/icons/Mi-24V_24.jpg deleted file mode 100644 index 97efd5185..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mi-24V_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mi-26_24.jpg b/resources/ui/units/aircrafts/icons/Mi-26_24.jpg deleted file mode 100644 index 9b0204efb..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mi-26_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mi-28N_24.jpg b/resources/ui/units/aircrafts/icons/Mi-28N_24.jpg deleted file mode 100644 index 48d8cc97c..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mi-28N_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mi-8MT_24.jpg b/resources/ui/units/aircrafts/icons/Mi-8MT_24.jpg deleted file mode 100644 index 052c9925f..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mi-8MT_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-15bis_24.jpg b/resources/ui/units/aircrafts/icons/MiG-15bis_24.jpg deleted file mode 100644 index e581ad935..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-15bis_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-19P_24.jpg b/resources/ui/units/aircrafts/icons/MiG-19P_24.jpg deleted file mode 100644 index 76aa4a3e5..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-19P_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-21Bis_24.jpg b/resources/ui/units/aircrafts/icons/MiG-21Bis_24.jpg deleted file mode 100644 index 07de7821c..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-21Bis_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-23MLD_24.jpg b/resources/ui/units/aircrafts/icons/MiG-23MLD_24.jpg deleted file mode 100644 index 876a6c2b5..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-23MLD_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-25PD_24.jpg b/resources/ui/units/aircrafts/icons/MiG-25PD_24.jpg deleted file mode 100644 index 861561c17..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-25PD_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-25RBT_24.jpg b/resources/ui/units/aircrafts/icons/MiG-25RBT_24.jpg deleted file mode 100644 index 379d07712..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-25RBT_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-27K_24.jpg b/resources/ui/units/aircrafts/icons/MiG-27K_24.jpg deleted file mode 100644 index 1f8dcbff4..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-27K_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-29A_24.jpg b/resources/ui/units/aircrafts/icons/MiG-29A_24.jpg deleted file mode 100644 index 2ad3e728b..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-29A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-29G_24.jpg b/resources/ui/units/aircrafts/icons/MiG-29G_24.jpg deleted file mode 100644 index b45b027d0..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-29G_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-29S_24.jpg b/resources/ui/units/aircrafts/icons/MiG-29S_24.jpg deleted file mode 100644 index 3cdf8e641..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-29S_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MiG-31_24.jpg b/resources/ui/units/aircrafts/icons/MiG-31_24.jpg deleted file mode 100644 index c1c1a238f..000000000 Binary files a/resources/ui/units/aircrafts/icons/MiG-31_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mirage 2000-5_24.jpg b/resources/ui/units/aircrafts/icons/Mirage 2000-5_24.jpg deleted file mode 100644 index bc5eeb842..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mirage 2000-5_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mirage-F1BE_24.jpg b/resources/ui/units/aircrafts/icons/Mirage-F1BE_24.jpg deleted file mode 100644 index 30b92f415..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mirage-F1BE_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mirage-F1B_24.jpg b/resources/ui/units/aircrafts/icons/Mirage-F1B_24.jpg deleted file mode 100644 index 6d7dd1f66..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mirage-F1B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mirage-F1C-200_24.jpg b/resources/ui/units/aircrafts/icons/Mirage-F1C-200_24.jpg deleted file mode 100644 index 608f8e94d..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mirage-F1C-200_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Mirage-F1CE_24.jpg b/resources/ui/units/aircrafts/icons/Mirage-F1CE_24.jpg deleted file mode 100644 index 0262cc346..000000000 Binary files a/resources/ui/units/aircrafts/icons/Mirage-F1CE_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/MosquitoFBMkVI_24.jpg b/resources/ui/units/aircrafts/icons/MosquitoFBMkVI_24.jpg deleted file mode 100644 index 0b34eb821..000000000 Binary files a/resources/ui/units/aircrafts/icons/MosquitoFBMkVI_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/OH-58D_24.jpg b/resources/ui/units/aircrafts/icons/OH-58D_24.jpg deleted file mode 100644 index 8392fe4f9..000000000 Binary files a/resources/ui/units/aircrafts/icons/OH-58D_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/P-47D-30_24.jpg b/resources/ui/units/aircrafts/icons/P-47D-30_24.jpg deleted file mode 100644 index b183cbb42..000000000 Binary files a/resources/ui/units/aircrafts/icons/P-47D-30_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/P-47D-30bl1_24.jpg b/resources/ui/units/aircrafts/icons/P-47D-30bl1_24.jpg deleted file mode 100644 index b183cbb42..000000000 Binary files a/resources/ui/units/aircrafts/icons/P-47D-30bl1_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/P-47D-40_24.jpg b/resources/ui/units/aircrafts/icons/P-47D-40_24.jpg deleted file mode 100644 index b183cbb42..000000000 Binary files a/resources/ui/units/aircrafts/icons/P-47D-40_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/P-51D-30-NA_24.jpg b/resources/ui/units/aircrafts/icons/P-51D-30-NA_24.jpg deleted file mode 100644 index a8601eabf..000000000 Binary files a/resources/ui/units/aircrafts/icons/P-51D-30-NA_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/P-51D_24.jpg b/resources/ui/units/aircrafts/icons/P-51D_24.jpg deleted file mode 100644 index a8601eabf..000000000 Binary files a/resources/ui/units/aircrafts/icons/P-51D_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Rafale_A_S_24.jpg b/resources/ui/units/aircrafts/icons/Rafale_A_S_24.jpg deleted file mode 100644 index 293afa73c..000000000 Binary files a/resources/ui/units/aircrafts/icons/Rafale_A_S_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Rafale_M_24.jpg b/resources/ui/units/aircrafts/icons/Rafale_M_24.jpg deleted file mode 100644 index 293afa73c..000000000 Binary files a/resources/ui/units/aircrafts/icons/Rafale_M_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/S-3B Tanker_24.jpg b/resources/ui/units/aircrafts/icons/S-3B Tanker_24.jpg deleted file mode 100644 index b04d9ce69..000000000 Binary files a/resources/ui/units/aircrafts/icons/S-3B Tanker_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/S-3B_24.jpg b/resources/ui/units/aircrafts/icons/S-3B_24.jpg deleted file mode 100644 index 422feba0b..000000000 Binary files a/resources/ui/units/aircrafts/icons/S-3B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SA342L_24.jpg b/resources/ui/units/aircrafts/icons/SA342L_24.jpg deleted file mode 100644 index 75e0a003f..000000000 Binary files a/resources/ui/units/aircrafts/icons/SA342L_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SA342M_24.jpg b/resources/ui/units/aircrafts/icons/SA342M_24.jpg deleted file mode 100644 index 78417f994..000000000 Binary files a/resources/ui/units/aircrafts/icons/SA342M_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SA342Minigun_24.jpg b/resources/ui/units/aircrafts/icons/SA342Minigun_24.jpg deleted file mode 100644 index 517e33c4b..000000000 Binary files a/resources/ui/units/aircrafts/icons/SA342Minigun_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SA342Mistral_24.jpg b/resources/ui/units/aircrafts/icons/SA342Mistral_24.jpg deleted file mode 100644 index b59d8d20b..000000000 Binary files a/resources/ui/units/aircrafts/icons/SA342Mistral_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SH-60B_24.jpg b/resources/ui/units/aircrafts/icons/SH-60B_24.jpg deleted file mode 100644 index 24365edba..000000000 Binary files a/resources/ui/units/aircrafts/icons/SH-60B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SpitfireLFMkIXCW_24.jpg b/resources/ui/units/aircrafts/icons/SpitfireLFMkIXCW_24.jpg deleted file mode 100644 index b2b5e77fc..000000000 Binary files a/resources/ui/units/aircrafts/icons/SpitfireLFMkIXCW_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/SpitfireLFMkIX_24.jpg b/resources/ui/units/aircrafts/icons/SpitfireLFMkIX_24.jpg deleted file mode 100644 index b2b5e77fc..000000000 Binary files a/resources/ui/units/aircrafts/icons/SpitfireLFMkIX_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-17M4_24.jpg b/resources/ui/units/aircrafts/icons/Su-17M4_24.jpg deleted file mode 100644 index 1af68e964..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-17M4_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-24MR_24.jpg b/resources/ui/units/aircrafts/icons/Su-24MR_24.jpg deleted file mode 100644 index 0a30caad5..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-24MR_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-24M_24.jpg b/resources/ui/units/aircrafts/icons/Su-24M_24.jpg deleted file mode 100644 index ca3e9241b..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-24M_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-25TM_24.jpg b/resources/ui/units/aircrafts/icons/Su-25TM_24.jpg deleted file mode 100644 index 452d3365a..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-25TM_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-25T_24.jpg b/resources/ui/units/aircrafts/icons/Su-25T_24.jpg deleted file mode 100644 index b0a75db9a..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-25T_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-25_24.jpg b/resources/ui/units/aircrafts/icons/Su-25_24.jpg deleted file mode 100644 index 61e7d5a20..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-25_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-27_24.jpg b/resources/ui/units/aircrafts/icons/Su-27_24.jpg deleted file mode 100644 index 2beaff029..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-27_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-30_24.jpg b/resources/ui/units/aircrafts/icons/Su-30_24.jpg deleted file mode 100644 index 7f492d73c..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-30_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-33_24.jpg b/resources/ui/units/aircrafts/icons/Su-33_24.jpg deleted file mode 100644 index 3bf34d0e6..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-33_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-34_24.jpg b/resources/ui/units/aircrafts/icons/Su-34_24.jpg deleted file mode 100644 index 3309ff97c..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-34_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Su-57_24.jpg b/resources/ui/units/aircrafts/icons/Su-57_24.jpg deleted file mode 100644 index adf32207a..000000000 Binary files a/resources/ui/units/aircrafts/icons/Su-57_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tornado GR4_24.jpg b/resources/ui/units/aircrafts/icons/Tornado GR4_24.jpg deleted file mode 100644 index b71e5b4ea..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tornado GR4_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tornado IDS_24.jpg b/resources/ui/units/aircrafts/icons/Tornado IDS_24.jpg deleted file mode 100644 index 0464a6709..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tornado IDS_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tornado_24.jpg b/resources/ui/units/aircrafts/icons/Tornado_24.jpg deleted file mode 100644 index 9e9c00e13..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tornado_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tu-142_24.jpg b/resources/ui/units/aircrafts/icons/Tu-142_24.jpg deleted file mode 100644 index 65c377a6d..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tu-142_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tu-160_24.jpg b/resources/ui/units/aircrafts/icons/Tu-160_24.jpg deleted file mode 100644 index 2b1f09abf..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tu-160_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tu-22M3_24.jpg b/resources/ui/units/aircrafts/icons/Tu-22M3_24.jpg deleted file mode 100644 index 290558f78..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tu-22M3_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Tu-95MS_24.jpg b/resources/ui/units/aircrafts/icons/Tu-95MS_24.jpg deleted file mode 100644 index 446c0014a..000000000 Binary files a/resources/ui/units/aircrafts/icons/Tu-95MS_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/UH-1H_24.jpg b/resources/ui/units/aircrafts/icons/UH-1H_24.jpg deleted file mode 100644 index 423db195e..000000000 Binary files a/resources/ui/units/aircrafts/icons/UH-1H_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/UH-60A_24.jpg b/resources/ui/units/aircrafts/icons/UH-60A_24.jpg deleted file mode 100644 index f26d9a4d2..000000000 Binary files a/resources/ui/units/aircrafts/icons/UH-60A_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/UH-60L_24.jpg b/resources/ui/units/aircrafts/icons/UH-60L_24.jpg deleted file mode 100644 index c6f469d44..000000000 Binary files a/resources/ui/units/aircrafts/icons/UH-60L_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/VSN_F104G_24.jpg b/resources/ui/units/aircrafts/icons/VSN_F104G_24.jpg deleted file mode 100644 index aaca5aab5..000000000 Binary files a/resources/ui/units/aircrafts/icons/VSN_F104G_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/VSN_F104S_24.jpg b/resources/ui/units/aircrafts/icons/VSN_F104S_24.jpg deleted file mode 100644 index 4a946060f..000000000 Binary files a/resources/ui/units/aircrafts/icons/VSN_F104S_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/VSN_F104S_AG_24.jpg b/resources/ui/units/aircrafts/icons/VSN_F104S_AG_24.jpg deleted file mode 100644 index 4a946060f..000000000 Binary files a/resources/ui/units/aircrafts/icons/VSN_F104S_AG_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/VSN_F4B_24.jpg b/resources/ui/units/aircrafts/icons/VSN_F4B_24.jpg deleted file mode 100644 index 6db8e71df..000000000 Binary files a/resources/ui/units/aircrafts/icons/VSN_F4B_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/VSN_F4C_24.jpg b/resources/ui/units/aircrafts/icons/VSN_F4C_24.jpg deleted file mode 100644 index 37e20dd52..000000000 Binary files a/resources/ui/units/aircrafts/icons/VSN_F4C_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/WingLoong-I_24.jpg b/resources/ui/units/aircrafts/icons/WingLoong-I_24.jpg deleted file mode 100644 index 32feeb368..000000000 Binary files a/resources/ui/units/aircrafts/icons/WingLoong-I_24.jpg and /dev/null differ diff --git a/resources/ui/units/aircrafts/icons/Yak-40_24.jpg b/resources/ui/units/aircrafts/icons/Yak-40_24.jpg deleted file mode 100644 index 80aa9cb95..000000000 Binary files a/resources/ui/units/aircrafts/icons/Yak-40_24.jpg and /dev/null differ diff --git a/resources/ui/units/buildings/.Ammunition depot.png b/resources/ui/units/buildings/.Ammunition depot.png deleted file mode 100644 index 3c17b0e2a..000000000 Binary files a/resources/ui/units/buildings/.Ammunition depot.png and /dev/null differ diff --git a/resources/ui/units/buildings/.Command Center.png b/resources/ui/units/buildings/.Command Center.png deleted file mode 100644 index 4e309d130..000000000 Binary files a/resources/ui/units/buildings/.Command Center.png and /dev/null differ diff --git a/resources/ui/units/buildings/Barracks 2.png b/resources/ui/units/buildings/Barracks 2.png deleted file mode 100644 index c25e5e01f..000000000 Binary files a/resources/ui/units/buildings/Barracks 2.png and /dev/null differ diff --git a/resources/ui/units/buildings/Chemical Tank A.png b/resources/ui/units/buildings/Chemical Tank A.png deleted file mode 100644 index 1311207b3..000000000 Binary files a/resources/ui/units/buildings/Chemical Tank A.png and /dev/null differ diff --git a/resources/ui/units/buildings/Comms tower M.png b/resources/ui/units/buildings/Comms tower M.png deleted file mode 100644 index 388fafff3..000000000 Binary files a/resources/ui/units/buildings/Comms tower M.png and /dev/null differ diff --git a/resources/ui/units/buildings/Electric power box.png b/resources/ui/units/buildings/Electric power box.png deleted file mode 100644 index 830a64136..000000000 Binary files a/resources/ui/units/buildings/Electric power box.png and /dev/null differ diff --git a/resources/ui/units/buildings/FARP Ammo Dump Coating.png b/resources/ui/units/buildings/FARP Ammo Dump Coating.png deleted file mode 100644 index 95840b1c2..000000000 Binary files a/resources/ui/units/buildings/FARP Ammo Dump Coating.png and /dev/null differ diff --git a/resources/ui/units/buildings/FARP CP Blindage.png b/resources/ui/units/buildings/FARP CP Blindage.png deleted file mode 100644 index 0c7db6fb9..000000000 Binary files a/resources/ui/units/buildings/FARP CP Blindage.png and /dev/null differ diff --git a/resources/ui/units/buildings/FARP Fuel Depot.png b/resources/ui/units/buildings/FARP Fuel Depot.png deleted file mode 100644 index d93a50c7f..000000000 Binary files a/resources/ui/units/buildings/FARP Fuel Depot.png and /dev/null differ diff --git a/resources/ui/units/buildings/FARP Tent.png b/resources/ui/units/buildings/FARP Tent.png deleted file mode 100644 index 199af9636..000000000 Binary files a/resources/ui/units/buildings/FARP Tent.png and /dev/null differ diff --git a/resources/ui/units/buildings/Farm A.png b/resources/ui/units/buildings/Farm A.png deleted file mode 100644 index 787e81170..000000000 Binary files a/resources/ui/units/buildings/Farm A.png and /dev/null differ diff --git a/resources/ui/units/buildings/Farm B.png b/resources/ui/units/buildings/Farm B.png deleted file mode 100644 index c889a8c05..000000000 Binary files a/resources/ui/units/buildings/Farm B.png and /dev/null differ diff --git a/resources/ui/units/buildings/Fire Control Bunker.png b/resources/ui/units/buildings/Fire Control Bunker.png deleted file mode 100644 index 5294b6800..000000000 Binary files a/resources/ui/units/buildings/Fire Control Bunker.png and /dev/null differ diff --git a/resources/ui/units/buildings/Garage B.png b/resources/ui/units/buildings/Garage B.png deleted file mode 100644 index b495a4d47..000000000 Binary files a/resources/ui/units/buildings/Garage B.png and /dev/null differ diff --git a/resources/ui/units/buildings/Garage small B.png b/resources/ui/units/buildings/Garage small B.png deleted file mode 100644 index f04794d20..000000000 Binary files a/resources/ui/units/buildings/Garage small B.png and /dev/null differ diff --git a/resources/ui/units/buildings/Hangar A.png b/resources/ui/units/buildings/Hangar A.png deleted file mode 100644 index 0eb1a3013..000000000 Binary files a/resources/ui/units/buildings/Hangar A.png and /dev/null differ diff --git a/resources/ui/units/buildings/Hangar B.png b/resources/ui/units/buildings/Hangar B.png deleted file mode 100644 index 96a28496f..000000000 Binary files a/resources/ui/units/buildings/Hangar B.png and /dev/null differ diff --git a/resources/ui/units/buildings/Oil derrick.png b/resources/ui/units/buildings/Oil derrick.png deleted file mode 100644 index 5a3c5cb43..000000000 Binary files a/resources/ui/units/buildings/Oil derrick.png and /dev/null differ diff --git a/resources/ui/units/buildings/Oil platform.png b/resources/ui/units/buildings/Oil platform.png deleted file mode 100644 index c548fe7ce..000000000 Binary files a/resources/ui/units/buildings/Oil platform.png and /dev/null differ diff --git a/resources/ui/units/buildings/Pump station.png b/resources/ui/units/buildings/Pump station.png deleted file mode 100644 index 24bc23d82..000000000 Binary files a/resources/ui/units/buildings/Pump station.png and /dev/null differ diff --git a/resources/ui/units/buildings/Repair Workshop.png b/resources/ui/units/buildings/Repair Workshop.png deleted file mode 100644 index 273291c70..000000000 Binary files a/resources/ui/units/buildings/Repair Workshop.png and /dev/null differ diff --git a/resources/ui/units/buildings/SK_C_28_naval_gun.png b/resources/ui/units/buildings/SK_C_28_naval_gun.png deleted file mode 100644 index 909f62092..000000000 Binary files a/resources/ui/units/buildings/SK_C_28_naval_gun.png and /dev/null differ diff --git a/resources/ui/units/buildings/Subsidiary structure 2.png b/resources/ui/units/buildings/Subsidiary structure 2.png deleted file mode 100644 index daa22d4d5..000000000 Binary files a/resources/ui/units/buildings/Subsidiary structure 2.png and /dev/null differ diff --git a/resources/ui/units/buildings/TV tower.png b/resources/ui/units/buildings/TV tower.png deleted file mode 100644 index 6b7f514a8..000000000 Binary files a/resources/ui/units/buildings/TV tower.png and /dev/null differ diff --git a/resources/ui/units/buildings/Tank 2.png b/resources/ui/units/buildings/Tank 2.png deleted file mode 100644 index 77faa07be..000000000 Binary files a/resources/ui/units/buildings/Tank 2.png and /dev/null differ diff --git a/resources/ui/units/buildings/Tank 3.png b/resources/ui/units/buildings/Tank 3.png deleted file mode 100644 index 8d807877b..000000000 Binary files a/resources/ui/units/buildings/Tank 3.png and /dev/null differ diff --git a/resources/ui/units/buildings/Tank.png b/resources/ui/units/buildings/Tank.png deleted file mode 100644 index 06dcaee2b..000000000 Binary files a/resources/ui/units/buildings/Tank.png and /dev/null differ diff --git a/resources/ui/units/buildings/Tech combine.png b/resources/ui/units/buildings/Tech combine.png deleted file mode 100644 index e58dfa56e..000000000 Binary files a/resources/ui/units/buildings/Tech combine.png and /dev/null differ diff --git a/resources/ui/units/buildings/Tech hangar A.png b/resources/ui/units/buildings/Tech hangar A.png deleted file mode 100644 index 423ba0cfd..000000000 Binary files a/resources/ui/units/buildings/Tech hangar A.png and /dev/null differ diff --git a/resources/ui/units/buildings/Warehouse.png b/resources/ui/units/buildings/Warehouse.png deleted file mode 100644 index dc74ede4e..000000000 Binary files a/resources/ui/units/buildings/Warehouse.png and /dev/null differ diff --git a/resources/ui/units/buildings/Watch tower armed.png b/resources/ui/units/buildings/Watch tower armed.png deleted file mode 100644 index dd0889eb5..000000000 Binary files a/resources/ui/units/buildings/Watch tower armed.png and /dev/null differ diff --git a/resources/ui/units/buildings/Workshop A.png b/resources/ui/units/buildings/Workshop A.png deleted file mode 100644 index fcb202ab4..000000000 Binary files a/resources/ui/units/buildings/Workshop A.png and /dev/null differ diff --git a/resources/ui/units/buildings/dead.png b/resources/ui/units/buildings/dead.png deleted file mode 100644 index 7b2188582..000000000 Binary files a/resources/ui/units/buildings/dead.png and /dev/null differ diff --git a/resources/ui/units/buildings/house2arm.png b/resources/ui/units/buildings/house2arm.png deleted file mode 100644 index dd0889eb5..000000000 Binary files a/resources/ui/units/buildings/house2arm.png and /dev/null differ diff --git a/resources/ui/units/buildings/missing.png b/resources/ui/units/buildings/missing.png deleted file mode 100644 index 88bc23019..000000000 Binary files a/resources/ui/units/buildings/missing.png and /dev/null differ diff --git a/resources/ui/units/readme.md b/resources/ui/units/readme.md deleted file mode 100644 index 96c96f1a2..000000000 --- a/resources/ui/units/readme.md +++ /dev/null @@ -1,29 +0,0 @@ -In this folder are icons for the different units in DCS / DCS Liberation. - -# How were these retrieved : -- I took screenshoot of the units from the encyclopedia in DCS. If you want to add more pictures, please do the same, so that the units have the same background. -- Then resized all the image so that have static size. Aspect ratio is not perfect, but it's hard to notice on such small image. - -```python - -import os -from PIL import Image - -for img_name in os.listdir("."): - if os.path.isfile(img_name) and img_name.endswith(".png"): - print(img_name) - img = Image.open(img_name) - img = img.resize((64,24), Image.ANTIALIAS) - img.save('./out/' + img_name[:-4] + "_24.jpg") - -``` - -You need PIL to run the script : - -``` -pip install PIL -``` - -If you want access to get my high res screenshoot, i still have them, but to reduce size and ram usage, i believe it's better to use super small jpg icons instead. - -@Khopa \ No newline at end of file diff --git a/resources/ui/units/ships/CVN_71.png b/resources/ui/units/ships/CVN_71.png deleted file mode 100644 index c4c60c013..000000000 Binary files a/resources/ui/units/ships/CVN_71.png and /dev/null differ diff --git a/resources/ui/units/ships/CVN_72.png b/resources/ui/units/ships/CVN_72.png deleted file mode 100644 index f77e4d379..000000000 Binary files a/resources/ui/units/ships/CVN_72.png and /dev/null differ diff --git a/resources/ui/units/ships/CVN_73.png b/resources/ui/units/ships/CVN_73.png deleted file mode 100644 index ee599527d..000000000 Binary files a/resources/ui/units/ships/CVN_73.png and /dev/null differ diff --git a/resources/ui/units/ships/CVN_75.png b/resources/ui/units/ships/CVN_75.png deleted file mode 100644 index 66809f562..000000000 Binary files a/resources/ui/units/ships/CVN_75.png and /dev/null differ diff --git a/resources/ui/units/ships/CV_1143_5.png b/resources/ui/units/ships/CV_1143_5.png deleted file mode 100644 index 2d7783a66..000000000 Binary files a/resources/ui/units/ships/CV_1143_5.png and /dev/null differ diff --git a/resources/ui/units/ships/Forrestal.png b/resources/ui/units/ships/Forrestal.png deleted file mode 100644 index 6d37f3ef5..000000000 Binary files a/resources/ui/units/ships/Forrestal.png and /dev/null differ diff --git a/resources/ui/units/ships/KUZNECOW.png b/resources/ui/units/ships/KUZNECOW.png deleted file mode 100644 index a22ad03d8..000000000 Binary files a/resources/ui/units/ships/KUZNECOW.png and /dev/null differ diff --git a/resources/ui/units/ships/LHA_Tarawa.png b/resources/ui/units/ships/LHA_Tarawa.png deleted file mode 100644 index 7f2a68e93..000000000 Binary files a/resources/ui/units/ships/LHA_Tarawa.png and /dev/null differ diff --git a/resources/ui/units/ships/Stennis.png b/resources/ui/units/ships/Stennis.png deleted file mode 100644 index f9aadd03b..000000000 Binary files a/resources/ui/units/ships/Stennis.png and /dev/null differ diff --git a/resources/ui/units/ships/Type_071.png b/resources/ui/units/ships/Type_071.png deleted file mode 100644 index d3370fa83..000000000 Binary files a/resources/ui/units/ships/Type_071.png and /dev/null differ diff --git a/resources/ui/units/ships/VINSON.png b/resources/ui/units/ships/VINSON.png deleted file mode 100644 index 45b963c06..000000000 Binary files a/resources/ui/units/ships/VINSON.png and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/2S6 Tunguska.jpg b/resources/ui/units/vehicles/banners/2S6 Tunguska.jpg deleted file mode 100644 index e1e1e70f0..000000000 Binary files a/resources/ui/units/vehicles/banners/2S6 Tunguska.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/BMP-1.jpg b/resources/ui/units/vehicles/banners/BMP-1.jpg deleted file mode 100644 index 18beb6058..000000000 Binary files a/resources/ui/units/vehicles/banners/BMP-1.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/BMP-2.jpg b/resources/ui/units/vehicles/banners/BMP-2.jpg deleted file mode 100644 index 35871ab62..000000000 Binary files a/resources/ui/units/vehicles/banners/BMP-2.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/BMP-3.jpg b/resources/ui/units/vehicles/banners/BMP-3.jpg deleted file mode 100644 index 8468516be..000000000 Binary files a/resources/ui/units/vehicles/banners/BMP-3.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/BTR-80.jpg b/resources/ui/units/vehicles/banners/BTR-80.jpg deleted file mode 100644 index 769b848d2..000000000 Binary files a/resources/ui/units/vehicles/banners/BTR-80.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/BTR-82A.jpg b/resources/ui/units/vehicles/banners/BTR-82A.jpg deleted file mode 100644 index 400c03979..000000000 Binary files a/resources/ui/units/vehicles/banners/BTR-82A.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Chieftain_mk3.jpg b/resources/ui/units/vehicles/banners/Chieftain_mk3.jpg deleted file mode 100644 index f626812f8..000000000 Binary files a/resources/ui/units/vehicles/banners/Chieftain_mk3.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/HQ-7_LN_SP.jpg b/resources/ui/units/vehicles/banners/HQ-7_LN_SP.jpg deleted file mode 100644 index aa028a8f8..000000000 Binary files a/resources/ui/units/vehicles/banners/HQ-7_LN_SP.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/LAV-25.jpg b/resources/ui/units/vehicles/banners/LAV-25.jpg deleted file mode 100644 index 11232a68a..000000000 Binary files a/resources/ui/units/vehicles/banners/LAV-25.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Leopard-2.jpg b/resources/ui/units/vehicles/banners/Leopard-2.jpg deleted file mode 100644 index e7e70eac8..000000000 Binary files a/resources/ui/units/vehicles/banners/Leopard-2.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Leopard1A3.jpg b/resources/ui/units/vehicles/banners/Leopard1A3.jpg deleted file mode 100644 index 4c3643afa..000000000 Binary files a/resources/ui/units/vehicles/banners/Leopard1A3.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M-1 Abrams.jpg b/resources/ui/units/vehicles/banners/M-1 Abrams.jpg deleted file mode 100644 index 65412bcab..000000000 Binary files a/resources/ui/units/vehicles/banners/M-1 Abrams.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M-109.jpg b/resources/ui/units/vehicles/banners/M-109.jpg deleted file mode 100644 index 2fca5a5b2..000000000 Binary files a/resources/ui/units/vehicles/banners/M-109.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M-113.jpg b/resources/ui/units/vehicles/banners/M-113.jpg deleted file mode 100644 index 1489245b3..000000000 Binary files a/resources/ui/units/vehicles/banners/M-113.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M-2 Bradley.jpg b/resources/ui/units/vehicles/banners/M-2 Bradley.jpg deleted file mode 100644 index 26fb99fce..000000000 Binary files a/resources/ui/units/vehicles/banners/M-2 Bradley.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M1043 HMMWV Armament.jpg b/resources/ui/units/vehicles/banners/M1043 HMMWV Armament.jpg deleted file mode 100644 index 375e02555..000000000 Binary files a/resources/ui/units/vehicles/banners/M1043 HMMWV Armament.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M1045 HMMWV TOW.jpg b/resources/ui/units/vehicles/banners/M1045 HMMWV TOW.jpg deleted file mode 100644 index 58a4e2bb6..000000000 Binary files a/resources/ui/units/vehicles/banners/M1045 HMMWV TOW.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M1097 Avenger.jpg b/resources/ui/units/vehicles/banners/M1097 Avenger.jpg deleted file mode 100644 index 3365acdb9..000000000 Binary files a/resources/ui/units/vehicles/banners/M1097 Avenger.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M1134 Stryker ATGM.jpg b/resources/ui/units/vehicles/banners/M1134 Stryker ATGM.jpg deleted file mode 100644 index b051f0a3a..000000000 Binary files a/resources/ui/units/vehicles/banners/M1134 Stryker ATGM.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/M6 Linebacker.jpg b/resources/ui/units/vehicles/banners/M6 Linebacker.jpg deleted file mode 100644 index 9a7576759..000000000 Binary files a/resources/ui/units/vehicles/banners/M6 Linebacker.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/MLRS.jpg b/resources/ui/units/vehicles/banners/MLRS.jpg deleted file mode 100644 index 74fadbdb4..000000000 Binary files a/resources/ui/units/vehicles/banners/MLRS.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Marder.jpg b/resources/ui/units/vehicles/banners/Marder.jpg deleted file mode 100644 index ab7137f6b..000000000 Binary files a/resources/ui/units/vehicles/banners/Marder.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Merkava_Mk4.jpg b/resources/ui/units/vehicles/banners/Merkava_Mk4.jpg deleted file mode 100644 index 4795e3ac5..000000000 Binary files a/resources/ui/units/vehicles/banners/Merkava_Mk4.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/SAU 2-C9.jpg b/resources/ui/units/vehicles/banners/SAU 2-C9.jpg deleted file mode 100644 index ad1db6818..000000000 Binary files a/resources/ui/units/vehicles/banners/SAU 2-C9.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/SAU Msta.jpg b/resources/ui/units/vehicles/banners/SAU Msta.jpg deleted file mode 100644 index 9df649c42..000000000 Binary files a/resources/ui/units/vehicles/banners/SAU Msta.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Smerch_HE.jpg b/resources/ui/units/vehicles/banners/Smerch_HE.jpg deleted file mode 100644 index 7d0fbb880..000000000 Binary files a/resources/ui/units/vehicles/banners/Smerch_HE.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/T-55.jpg b/resources/ui/units/vehicles/banners/T-55.jpg deleted file mode 100644 index e01cc8359..000000000 Binary files a/resources/ui/units/vehicles/banners/T-55.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/T-72B3.jpg b/resources/ui/units/vehicles/banners/T-72B3.jpg deleted file mode 100644 index 8535701cb..000000000 Binary files a/resources/ui/units/vehicles/banners/T-72B3.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/T-80UD.jpg b/resources/ui/units/vehicles/banners/T-80UD.jpg deleted file mode 100644 index 4f6af349d..000000000 Binary files a/resources/ui/units/vehicles/banners/T-80UD.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/T-90.jpg b/resources/ui/units/vehicles/banners/T-90.jpg deleted file mode 100644 index 1c554375a..000000000 Binary files a/resources/ui/units/vehicles/banners/T-90.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/UAZ-469.jpg b/resources/ui/units/vehicles/banners/UAZ-469.jpg deleted file mode 100644 index a228b2ff4..000000000 Binary files a/resources/ui/units/vehicles/banners/UAZ-469.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Uragan_BM-27.jpg b/resources/ui/units/vehicles/banners/Uragan_BM-27.jpg deleted file mode 100644 index becf020bc..000000000 Binary files a/resources/ui/units/vehicles/banners/Uragan_BM-27.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Ural-375 ZU-23 Insurgent.jpg b/resources/ui/units/vehicles/banners/Ural-375 ZU-23 Insurgent.jpg deleted file mode 100644 index 55642c27b..000000000 Binary files a/resources/ui/units/vehicles/banners/Ural-375 ZU-23 Insurgent.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Ural-375 ZU-23.jpg b/resources/ui/units/vehicles/banners/Ural-375 ZU-23.jpg deleted file mode 100644 index 55642c27b..000000000 Binary files a/resources/ui/units/vehicles/banners/Ural-375 ZU-23.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Ural-375.jpg b/resources/ui/units/vehicles/banners/Ural-375.jpg deleted file mode 100644 index b6e41809a..000000000 Binary files a/resources/ui/units/vehicles/banners/Ural-375.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/VAB_Mephisto.jpg b/resources/ui/units/vehicles/banners/VAB_Mephisto.jpg deleted file mode 100644 index a5763b4b6..000000000 Binary files a/resources/ui/units/vehicles/banners/VAB_Mephisto.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/Vulcan.jpg b/resources/ui/units/vehicles/banners/Vulcan.jpg deleted file mode 100644 index 0182f5561..000000000 Binary files a/resources/ui/units/vehicles/banners/Vulcan.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/ZBD04A.jpg b/resources/ui/units/vehicles/banners/ZBD04A.jpg deleted file mode 100644 index d14af06da..000000000 Binary files a/resources/ui/units/vehicles/banners/ZBD04A.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/ZSU-23-4 Shilka.jpg b/resources/ui/units/vehicles/banners/ZSU-23-4 Shilka.jpg deleted file mode 100644 index 7b90785d6..000000000 Binary files a/resources/ui/units/vehicles/banners/ZSU-23-4 Shilka.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/ZSU_57_2.jpg b/resources/ui/units/vehicles/banners/ZSU_57_2.jpg deleted file mode 100644 index 359aef46f..000000000 Binary files a/resources/ui/units/vehicles/banners/ZSU_57_2.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/ZTZ96B.jpg b/resources/ui/units/vehicles/banners/ZTZ96B.jpg deleted file mode 100644 index 942ecbefb..000000000 Binary files a/resources/ui/units/vehicles/banners/ZTZ96B.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/banners/leopard-2A4.jpg b/resources/ui/units/vehicles/banners/leopard-2A4.jpg deleted file mode 100644 index 56d8d7ee2..000000000 Binary files a/resources/ui/units/vehicles/banners/leopard-2A4.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/2S6 Tunguska_24.jpg b/resources/ui/units/vehicles/icons/2S6 Tunguska_24.jpg deleted file mode 100644 index 94e5ee277..000000000 Binary files a/resources/ui/units/vehicles/icons/2S6 Tunguska_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/5p73 s-125 ln_24.jpg b/resources/ui/units/vehicles/icons/5p73 s-125 ln_24.jpg deleted file mode 100644 index a56a49564..000000000 Binary files a/resources/ui/units/vehicles/icons/5p73 s-125 ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/AAV-7_24.jpg b/resources/ui/units/vehicles/icons/AAV-7_24.jpg deleted file mode 100644 index c1b33ce6a..000000000 Binary files a/resources/ui/units/vehicles/icons/AAV-7_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BMD-1_24.jpg b/resources/ui/units/vehicles/icons/BMD-1_24.jpg deleted file mode 100644 index 43c88734e..000000000 Binary files a/resources/ui/units/vehicles/icons/BMD-1_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BMP-1_24.jpg b/resources/ui/units/vehicles/icons/BMP-1_24.jpg deleted file mode 100644 index 262049c8e..000000000 Binary files a/resources/ui/units/vehicles/icons/BMP-1_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BMP-2_24.jpg b/resources/ui/units/vehicles/icons/BMP-2_24.jpg deleted file mode 100644 index eda8b8e27..000000000 Binary files a/resources/ui/units/vehicles/icons/BMP-2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BMP-3_24.jpg b/resources/ui/units/vehicles/icons/BMP-3_24.jpg deleted file mode 100644 index 99bd096c2..000000000 Binary files a/resources/ui/units/vehicles/icons/BMP-3_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BRDM-2_24.jpg b/resources/ui/units/vehicles/icons/BRDM-2_24.jpg deleted file mode 100644 index cda664247..000000000 Binary files a/resources/ui/units/vehicles/icons/BRDM-2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BTR-80_24.jpg b/resources/ui/units/vehicles/icons/BTR-80_24.jpg deleted file mode 100644 index ca3f814e2..000000000 Binary files a/resources/ui/units/vehicles/icons/BTR-80_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BTR-82A_24.jpg b/resources/ui/units/vehicles/icons/BTR-82A_24.jpg deleted file mode 100644 index e5454a1d6..000000000 Binary files a/resources/ui/units/vehicles/icons/BTR-82A_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/BTR-RD_24.jpg b/resources/ui/units/vehicles/icons/BTR-RD_24.jpg deleted file mode 100644 index be9ac063d..000000000 Binary files a/resources/ui/units/vehicles/icons/BTR-RD_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Bedford_MWD_24.jpg b/resources/ui/units/vehicles/icons/Bedford_MWD_24.jpg deleted file mode 100644 index 3bc240743..000000000 Binary files a/resources/ui/units/vehicles/icons/Bedford_MWD_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Blitz_36-6700A_24.jpg b/resources/ui/units/vehicles/icons/Blitz_36-6700A_24.jpg deleted file mode 100644 index 8fd930055..000000000 Binary files a/resources/ui/units/vehicles/icons/Blitz_36-6700A_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/CCKW 353_24.jpg b/resources/ui/units/vehicles/icons/CCKW 353_24.jpg deleted file mode 100644 index ceb33eb2c..000000000 Binary files a/resources/ui/units/vehicles/icons/CCKW 353_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Centaur_IV_24.jpg b/resources/ui/units/vehicles/icons/Centaur_IV_24.jpg deleted file mode 100644 index dcbabd276..000000000 Binary files a/resources/ui/units/vehicles/icons/Centaur_IV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Challenger 2_24.jpg b/resources/ui/units/vehicles/icons/Challenger 2_24.jpg deleted file mode 100644 index 7a5e0df96..000000000 Binary files a/resources/ui/units/vehicles/icons/Challenger 2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Churchill_VII_24.jpg b/resources/ui/units/vehicles/icons/Churchill_VII_24.jpg deleted file mode 100644 index 2f46a79a7..000000000 Binary files a/resources/ui/units/vehicles/icons/Churchill_VII_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Cobra_24.jpg b/resources/ui/units/vehicles/icons/Cobra_24.jpg deleted file mode 100644 index 58ac6182a..000000000 Binary files a/resources/ui/units/vehicles/icons/Cobra_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Cromwell_IV_24.jpg b/resources/ui/units/vehicles/icons/Cromwell_IV_24.jpg deleted file mode 100644 index adf204786..000000000 Binary files a/resources/ui/units/vehicles/icons/Cromwell_IV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Daimler_AC_24.jpg b/resources/ui/units/vehicles/icons/Daimler_AC_24.jpg deleted file mode 100644 index a81db45e6..000000000 Binary files a/resources/ui/units/vehicles/icons/Daimler_AC_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Elefant_SdKfz_184_24.jpg b/resources/ui/units/vehicles/icons/Elefant_SdKfz_184_24.jpg deleted file mode 100644 index 210967d7e..000000000 Binary files a/resources/ui/units/vehicles/icons/Elefant_SdKfz_184_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Flakscheinwerfer_37_24.jpg b/resources/ui/units/vehicles/icons/Flakscheinwerfer_37_24.jpg deleted file mode 100644 index f0996252c..000000000 Binary files a/resources/ui/units/vehicles/icons/Flakscheinwerfer_37_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/FuMG-401_24.jpg b/resources/ui/units/vehicles/icons/FuMG-401_24.jpg deleted file mode 100644 index 9d60a3cc1..000000000 Binary files a/resources/ui/units/vehicles/icons/FuMG-401_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Gepard_24.jpg b/resources/ui/units/vehicles/icons/Gepard_24.jpg deleted file mode 100644 index f2775a847..000000000 Binary files a/resources/ui/units/vehicles/icons/Gepard_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Grad-Ural.jpg b/resources/ui/units/vehicles/icons/Grad-Ural.jpg deleted file mode 100644 index d2ceef285..000000000 Binary files a/resources/ui/units/vehicles/icons/Grad-Ural.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/HQ-7 Mobile Launcher_24.jpg b/resources/ui/units/vehicles/icons/HQ-7 Mobile Launcher_24.jpg deleted file mode 100644 index 7fd18f05b..000000000 Binary files a/resources/ui/units/vehicles/icons/HQ-7 Mobile Launcher_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/HQ-7 Mobile Radar_24.jpg b/resources/ui/units/vehicles/icons/HQ-7 Mobile Radar_24.jpg deleted file mode 100644 index 377709ef3..000000000 Binary files a/resources/ui/units/vehicles/icons/HQ-7 Mobile Radar_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Hawk ln_24.jpg b/resources/ui/units/vehicles/icons/Hawk ln_24.jpg deleted file mode 100644 index 08544b415..000000000 Binary files a/resources/ui/units/vehicles/icons/Hawk ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Hawk sr_24.jpg b/resources/ui/units/vehicles/icons/Hawk sr_24.jpg deleted file mode 100644 index 174088636..000000000 Binary files a/resources/ui/units/vehicles/icons/Hawk sr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Hawk tr_24.jpg b/resources/ui/units/vehicles/icons/Hawk tr_24.jpg deleted file mode 100644 index 7c1ae7529..000000000 Binary files a/resources/ui/units/vehicles/icons/Hawk tr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/JagdPz_IV_24.jpg b/resources/ui/units/vehicles/icons/JagdPz_IV_24.jpg deleted file mode 100644 index 2bc0c950f..000000000 Binary files a/resources/ui/units/vehicles/icons/JagdPz_IV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Jagdpanther_G1_24.jpg b/resources/ui/units/vehicles/icons/Jagdpanther_G1_24.jpg deleted file mode 100644 index 8505fe103..000000000 Binary files a/resources/ui/units/vehicles/icons/Jagdpanther_G1_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/KAMAZ Truck_24.jpg b/resources/ui/units/vehicles/icons/KAMAZ Truck_24.jpg deleted file mode 100644 index d7c549dce..000000000 Binary files a/resources/ui/units/vehicles/icons/KAMAZ Truck_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/KDO_Mod40_24.jpg b/resources/ui/units/vehicles/icons/KDO_Mod40_24.jpg deleted file mode 100644 index 76068edc6..000000000 Binary files a/resources/ui/units/vehicles/icons/KDO_Mod40_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Kub 1S91 str_24.jpg b/resources/ui/units/vehicles/icons/Kub 1S91 str_24.jpg deleted file mode 100644 index b8bcd6403..000000000 Binary files a/resources/ui/units/vehicles/icons/Kub 1S91 str_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Kub 2P25 ln_24.jpg b/resources/ui/units/vehicles/icons/Kub 2P25 ln_24.jpg deleted file mode 100644 index 7dd5bf4b1..000000000 Binary files a/resources/ui/units/vehicles/icons/Kub 2P25 ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Kubelwagen_82_24.jpg b/resources/ui/units/vehicles/icons/Kubelwagen_82_24.jpg deleted file mode 100644 index 019071045..000000000 Binary files a/resources/ui/units/vehicles/icons/Kubelwagen_82_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/LAV-25_24.jpg b/resources/ui/units/vehicles/icons/LAV-25_24.jpg deleted file mode 100644 index 170edeb1f..000000000 Binary files a/resources/ui/units/vehicles/icons/LAV-25_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Leclerc_24.jpg b/resources/ui/units/vehicles/icons/Leclerc_24.jpg deleted file mode 100644 index d722c3782..000000000 Binary files a/resources/ui/units/vehicles/icons/Leclerc_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Leopard 1A3_24.jpg b/resources/ui/units/vehicles/icons/Leopard 1A3_24.jpg deleted file mode 100644 index 7108ef340..000000000 Binary files a/resources/ui/units/vehicles/icons/Leopard 1A3_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Leopard-2_24.jpg b/resources/ui/units/vehicles/icons/Leopard-2_24.jpg deleted file mode 100644 index 6a58616fe..000000000 Binary files a/resources/ui/units/vehicles/icons/Leopard-2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M 818_24.jpg b/resources/ui/units/vehicles/icons/M 818_24.jpg deleted file mode 100644 index 23372bf0a..000000000 Binary files a/resources/ui/units/vehicles/icons/M 818_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M-1 Abrams_24.jpg b/resources/ui/units/vehicles/icons/M-1 Abrams_24.jpg deleted file mode 100644 index d0bf9a664..000000000 Binary files a/resources/ui/units/vehicles/icons/M-1 Abrams_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M-113_24.jpg b/resources/ui/units/vehicles/icons/M-113_24.jpg deleted file mode 100644 index 8319228dd..000000000 Binary files a/resources/ui/units/vehicles/icons/M-113_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M-163 Vulcan_24.jpg b/resources/ui/units/vehicles/icons/M-163 Vulcan_24.jpg deleted file mode 100644 index f5489310a..000000000 Binary files a/resources/ui/units/vehicles/icons/M-163 Vulcan_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M-2 Bradley_24.jpg b/resources/ui/units/vehicles/icons/M-2 Bradley_24.jpg deleted file mode 100644 index 037dddf1c..000000000 Binary files a/resources/ui/units/vehicles/icons/M-2 Bradley_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M-60_24.jpg b/resources/ui/units/vehicles/icons/M-60_24.jpg deleted file mode 100644 index 8e4e1b3ae..000000000 Binary files a/resources/ui/units/vehicles/icons/M-60_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1043 HMMWV Armament_24.jpg b/resources/ui/units/vehicles/icons/M1043 HMMWV Armament_24.jpg deleted file mode 100644 index f24eddfdf..000000000 Binary files a/resources/ui/units/vehicles/icons/M1043 HMMWV Armament_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1045 HMMWV TOW_24.jpg b/resources/ui/units/vehicles/icons/M1045 HMMWV TOW_24.jpg deleted file mode 100644 index c37355f06..000000000 Binary files a/resources/ui/units/vehicles/icons/M1045 HMMWV TOW_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1097 Avenger_24.jpg b/resources/ui/units/vehicles/icons/M1097 Avenger_24.jpg deleted file mode 100644 index 1ed509750..000000000 Binary files a/resources/ui/units/vehicles/icons/M1097 Avenger_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M109_24.jpg b/resources/ui/units/vehicles/icons/M109_24.jpg deleted file mode 100644 index 2d0994d6b..000000000 Binary files a/resources/ui/units/vehicles/icons/M109_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M10_GMC_24.jpg b/resources/ui/units/vehicles/icons/M10_GMC_24.jpg deleted file mode 100644 index c8c84ed6a..000000000 Binary files a/resources/ui/units/vehicles/icons/M10_GMC_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1126 Stryker ICV_24.jpg b/resources/ui/units/vehicles/icons/M1126 Stryker ICV_24.jpg deleted file mode 100644 index 0eafe997d..000000000 Binary files a/resources/ui/units/vehicles/icons/M1126 Stryker ICV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1128 Stryker MGS_24.jpg b/resources/ui/units/vehicles/icons/M1128 Stryker MGS_24.jpg deleted file mode 100644 index a899065aa..000000000 Binary files a/resources/ui/units/vehicles/icons/M1128 Stryker MGS_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1134 Stryker ATGM_24.jpg b/resources/ui/units/vehicles/icons/M1134 Stryker ATGM_24.jpg deleted file mode 100644 index 22ccbc68e..000000000 Binary files a/resources/ui/units/vehicles/icons/M1134 Stryker ATGM_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M12_GMC_24.jpg b/resources/ui/units/vehicles/icons/M12_GMC_24.jpg deleted file mode 100644 index fb047d17d..000000000 Binary files a/resources/ui/units/vehicles/icons/M12_GMC_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1A2_24.jpg b/resources/ui/units/vehicles/icons/M1A2_24.jpg deleted file mode 100644 index d0bf9a664..000000000 Binary files a/resources/ui/units/vehicles/icons/M1A2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M1_37mm_24.jpg b/resources/ui/units/vehicles/icons/M1_37mm_24.jpg deleted file mode 100644 index 4d9fd1f8a..000000000 Binary files a/resources/ui/units/vehicles/icons/M1_37mm_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M2A1_halftrack_24.jpg b/resources/ui/units/vehicles/icons/M2A1_halftrack_24.jpg deleted file mode 100644 index 42692c7d3..000000000 Binary files a/resources/ui/units/vehicles/icons/M2A1_halftrack_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M2A2_24.jpg b/resources/ui/units/vehicles/icons/M2A2_24.jpg deleted file mode 100644 index 037dddf1c..000000000 Binary files a/resources/ui/units/vehicles/icons/M2A2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M30_CC_24.jpg b/resources/ui/units/vehicles/icons/M30_CC_24.jpg deleted file mode 100644 index b25731fee..000000000 Binary files a/resources/ui/units/vehicles/icons/M30_CC_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M45_Quadmount_24.jpg b/resources/ui/units/vehicles/icons/M45_Quadmount_24.jpg deleted file mode 100644 index 640841bba..000000000 Binary files a/resources/ui/units/vehicles/icons/M45_Quadmount_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M48 Chaparral_24.jpg b/resources/ui/units/vehicles/icons/M48 Chaparral_24.jpg deleted file mode 100644 index 2d01a9cc1..000000000 Binary files a/resources/ui/units/vehicles/icons/M48 Chaparral_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M4A4_Sherman_FF_24.jpg b/resources/ui/units/vehicles/icons/M4A4_Sherman_FF_24.jpg deleted file mode 100644 index b34c4420c..000000000 Binary files a/resources/ui/units/vehicles/icons/M4A4_Sherman_FF_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M4_Sherman_24.jpg b/resources/ui/units/vehicles/icons/M4_Sherman_24.jpg deleted file mode 100644 index a902812ff..000000000 Binary files a/resources/ui/units/vehicles/icons/M4_Sherman_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M4_Tractor_24.jpg b/resources/ui/units/vehicles/icons/M4_Tractor_24.jpg deleted file mode 100644 index a9c8a3f1e..000000000 Binary files a/resources/ui/units/vehicles/icons/M4_Tractor_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M6 Linebacker_24.jpg b/resources/ui/units/vehicles/icons/M6 Linebacker_24.jpg deleted file mode 100644 index 615368daf..000000000 Binary files a/resources/ui/units/vehicles/icons/M6 Linebacker_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M818_24.jpg b/resources/ui/units/vehicles/icons/M818_24.jpg deleted file mode 100644 index 23372bf0a..000000000 Binary files a/resources/ui/units/vehicles/icons/M818_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/M8_Greyhound_24.jpg b/resources/ui/units/vehicles/icons/M8_Greyhound_24.jpg deleted file mode 100644 index 5f73175fe..000000000 Binary files a/resources/ui/units/vehicles/icons/M8_Greyhound_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/MCV-80 Warrior_24.jpg b/resources/ui/units/vehicles/icons/MCV-80 Warrior_24.jpg deleted file mode 100644 index c4dd91ef5..000000000 Binary files a/resources/ui/units/vehicles/icons/MCV-80 Warrior_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/MTLB_24.jpg b/resources/ui/units/vehicles/icons/MTLB_24.jpg deleted file mode 100644 index e91127231..000000000 Binary files a/resources/ui/units/vehicles/icons/MTLB_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Marder_24.jpg b/resources/ui/units/vehicles/icons/Marder_24.jpg deleted file mode 100644 index 3717e28d5..000000000 Binary files a/resources/ui/units/vehicles/icons/Marder_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Maschinensatz_33_24.jpg b/resources/ui/units/vehicles/icons/Maschinensatz_33_24.jpg deleted file mode 100644 index 08fd89844..000000000 Binary files a/resources/ui/units/vehicles/icons/Maschinensatz_33_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Merkava Mk4_24.jpg b/resources/ui/units/vehicles/icons/Merkava Mk4_24.jpg deleted file mode 100644 index dfd47a689..000000000 Binary files a/resources/ui/units/vehicles/icons/Merkava Mk4_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Osa 9A33 ln_24.jpg b/resources/ui/units/vehicles/icons/Osa 9A33 ln_24.jpg deleted file mode 100644 index 5efab07ad..000000000 Binary files a/resources/ui/units/vehicles/icons/Osa 9A33 ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/PLZ-05_24.jpg b/resources/ui/units/vehicles/icons/PLZ-05_24.jpg deleted file mode 100644 index c10e5fba0..000000000 Binary files a/resources/ui/units/vehicles/icons/PLZ-05_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot AMG_24.jpg b/resources/ui/units/vehicles/icons/Patriot AMG_24.jpg deleted file mode 100644 index 9ead9fc99..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot AMG_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot ECS_24.jpg b/resources/ui/units/vehicles/icons/Patriot ECS_24.jpg deleted file mode 100644 index b79e5811c..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot ECS_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot EPP_24.jpg b/resources/ui/units/vehicles/icons/Patriot EPP_24.jpg deleted file mode 100644 index 98f0c82de..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot EPP_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot ICC_24.jpg b/resources/ui/units/vehicles/icons/Patriot ICC_24.jpg deleted file mode 100644 index 2fba5af8c..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot ICC_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot ln_24.jpg b/resources/ui/units/vehicles/icons/Patriot ln_24.jpg deleted file mode 100644 index 7eb6ea24c..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Patriot str_24.jpg b/resources/ui/units/vehicles/icons/Patriot str_24.jpg deleted file mode 100644 index 01122769a..000000000 Binary files a/resources/ui/units/vehicles/icons/Patriot str_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Pz_IV_H_24.jpg b/resources/ui/units/vehicles/icons/Pz_IV_H_24.jpg deleted file mode 100644 index af0685949..000000000 Binary files a/resources/ui/units/vehicles/icons/Pz_IV_H_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Pz_V_Panther_G_24.jpg b/resources/ui/units/vehicles/icons/Pz_V_Panther_G_24.jpg deleted file mode 100644 index 00ba78519..000000000 Binary files a/resources/ui/units/vehicles/icons/Pz_V_Panther_G_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/QF_37_AA_24.jpg b/resources/ui/units/vehicles/icons/QF_37_AA_24.jpg deleted file mode 100644 index 82f60ec51..000000000 Binary files a/resources/ui/units/vehicles/icons/QF_37_AA_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Roland ADS_24.jpg b/resources/ui/units/vehicles/icons/Roland ADS_24.jpg deleted file mode 100644 index 3ee30605d..000000000 Binary files a/resources/ui/units/vehicles/icons/Roland ADS_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Roland Radar_24.jpg b/resources/ui/units/vehicles/icons/Roland Radar_24.jpg deleted file mode 100644 index 5969b934f..000000000 Binary files a/resources/ui/units/vehicles/icons/Roland Radar_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 40B6M tr_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 40B6M tr_24.jpg deleted file mode 100644 index 84b9ebecd..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 40B6M tr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 40B6MD sr_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 40B6MD sr_24.jpg deleted file mode 100644 index 3bb65acd6..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 40B6MD sr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 54K6 cp_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 54K6 cp_24.jpg deleted file mode 100644 index ce48f2edb..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 54K6 cp_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 5P85C ln_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 5P85C ln_24.jpg deleted file mode 100644 index e89639126..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 5P85C ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 5P85D ln_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 5P85D ln_24.jpg deleted file mode 100644 index c971df7ec..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 5P85D ln_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-300PS 64H6E sr_24.jpg b/resources/ui/units/vehicles/icons/S-300PS 64H6E sr_24.jpg deleted file mode 100644 index 79cb21cc8..000000000 Binary files a/resources/ui/units/vehicles/icons/S-300PS 64H6E sr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S-60_24.jpg b/resources/ui/units/vehicles/icons/S-60_24.jpg deleted file mode 100644 index 09a32ea4c..000000000 Binary files a/resources/ui/units/vehicles/icons/S-60_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/SAO 2-C9_24.jpg b/resources/ui/units/vehicles/icons/SAO 2-C9_24.jpg deleted file mode 100644 index 12903bbad..000000000 Binary files a/resources/ui/units/vehicles/icons/SAO 2-C9_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/SAU 2S3 Akatsia_24.jpg b/resources/ui/units/vehicles/icons/SAU 2S3 Akatsia_24.jpg deleted file mode 100644 index db08c8628..000000000 Binary files a/resources/ui/units/vehicles/icons/SAU 2S3 Akatsia_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/SAU Gvozdika_24.jpg b/resources/ui/units/vehicles/icons/SAU Gvozdika_24.jpg deleted file mode 100644 index 30719cb12..000000000 Binary files a/resources/ui/units/vehicles/icons/SAU Gvozdika_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/SAU Msta_24.jpg b/resources/ui/units/vehicles/icons/SAU Msta_24.jpg deleted file mode 100644 index 10ea12a47..000000000 Binary files a/resources/ui/units/vehicles/icons/SAU Msta_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/SNR_75V_24.jpg b/resources/ui/units/vehicles/icons/SNR_75V_24.jpg deleted file mode 100644 index 1d2ea6d84..000000000 Binary files a/resources/ui/units/vehicles/icons/SNR_75V_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/S_75M_Volhov_24.jpg b/resources/ui/units/vehicles/icons/S_75M_Volhov_24.jpg deleted file mode 100644 index 1d86c7b40..000000000 Binary files a/resources/ui/units/vehicles/icons/S_75M_Volhov_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Sd_Kfz_234_2_Puma_24.jpg b/resources/ui/units/vehicles/icons/Sd_Kfz_234_2_Puma_24.jpg deleted file mode 100644 index 2b5147813..000000000 Binary files a/resources/ui/units/vehicles/icons/Sd_Kfz_234_2_Puma_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Sd_Kfz_251_24.jpg b/resources/ui/units/vehicles/icons/Sd_Kfz_251_24.jpg deleted file mode 100644 index fc45fc952..000000000 Binary files a/resources/ui/units/vehicles/icons/Sd_Kfz_251_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Sd_Kfz_2_24.jpg b/resources/ui/units/vehicles/icons/Sd_Kfz_2_24.jpg deleted file mode 100644 index 0548a7a1d..000000000 Binary files a/resources/ui/units/vehicles/icons/Sd_Kfz_2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Sd_Kfz_7_24.jpg b/resources/ui/units/vehicles/icons/Sd_Kfz_7_24.jpg deleted file mode 100644 index ef52dc202..000000000 Binary files a/resources/ui/units/vehicles/icons/Sd_Kfz_7_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ShKH vz. 77 DANA_24.jpg b/resources/ui/units/vehicles/icons/ShKH vz. 77 DANA_24.jpg deleted file mode 100644 index 7268a89dd..000000000 Binary files a/resources/ui/units/vehicles/icons/ShKH vz. 77 DANA_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Shilka ZSU-23-4_24.jpg b/resources/ui/units/vehicles/icons/Shilka ZSU-23-4_24.jpg deleted file mode 100644 index 334dc0655..000000000 Binary files a/resources/ui/units/vehicles/icons/Shilka ZSU-23-4_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Strela-10M3_24.jpg b/resources/ui/units/vehicles/icons/Strela-10M3_24.jpg deleted file mode 100644 index 84917278f..000000000 Binary files a/resources/ui/units/vehicles/icons/Strela-10M3_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Stug_III_24.jpg b/resources/ui/units/vehicles/icons/Stug_III_24.jpg deleted file mode 100644 index 3539899e0..000000000 Binary files a/resources/ui/units/vehicles/icons/Stug_III_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Stug_IV_24.jpg b/resources/ui/units/vehicles/icons/Stug_IV_24.jpg deleted file mode 100644 index b1351db0a..000000000 Binary files a/resources/ui/units/vehicles/icons/Stug_IV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Sturmpanzer IV_24.jpg b/resources/ui/units/vehicles/icons/Sturmpanzer IV_24.jpg deleted file mode 100644 index 21349a153..000000000 Binary files a/resources/ui/units/vehicles/icons/Sturmpanzer IV_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-55_24.jpg b/resources/ui/units/vehicles/icons/T-55_24.jpg deleted file mode 100644 index e2d6c5e05..000000000 Binary files a/resources/ui/units/vehicles/icons/T-55_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-72B3_24.jpg b/resources/ui/units/vehicles/icons/T-72B3_24.jpg deleted file mode 100644 index 8f08c8934..000000000 Binary files a/resources/ui/units/vehicles/icons/T-72B3_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-72B_24.jpg b/resources/ui/units/vehicles/icons/T-72B_24.jpg deleted file mode 100644 index dc8c5ff37..000000000 Binary files a/resources/ui/units/vehicles/icons/T-72B_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-80UD_24.jpg b/resources/ui/units/vehicles/icons/T-80UD_24.jpg deleted file mode 100644 index 8537a9b3f..000000000 Binary files a/resources/ui/units/vehicles/icons/T-80UD_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-80U_24.jpg b/resources/ui/units/vehicles/icons/T-80U_24.jpg deleted file mode 100644 index 8537a9b3f..000000000 Binary files a/resources/ui/units/vehicles/icons/T-80U_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/T-90_24.jpg b/resources/ui/units/vehicles/icons/T-90_24.jpg deleted file mode 100644 index d79bcb4ce..000000000 Binary files a/resources/ui/units/vehicles/icons/T-90_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/TPZ_24.jpg b/resources/ui/units/vehicles/icons/TPZ_24.jpg deleted file mode 100644 index 425b9a825..000000000 Binary files a/resources/ui/units/vehicles/icons/TPZ_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Tetrarch_24.jpg b/resources/ui/units/vehicles/icons/Tetrarch_24.jpg deleted file mode 100644 index cae41d376..000000000 Binary files a/resources/ui/units/vehicles/icons/Tetrarch_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Tiger_II_H_24.jpg b/resources/ui/units/vehicles/icons/Tiger_II_H_24.jpg deleted file mode 100644 index 0e6c9e9a7..000000000 Binary files a/resources/ui/units/vehicles/icons/Tiger_II_H_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Tiger_I_24.jpg b/resources/ui/units/vehicles/icons/Tiger_I_24.jpg deleted file mode 100644 index 40b257c88..000000000 Binary files a/resources/ui/units/vehicles/icons/Tiger_I_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Tor 9A331_24.jpg b/resources/ui/units/vehicles/icons/Tor 9A331_24.jpg deleted file mode 100644 index 7fc3c6ded..000000000 Binary files a/resources/ui/units/vehicles/icons/Tor 9A331_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Tunguska 2C6M_24.jpg b/resources/ui/units/vehicles/icons/Tunguska 2C6M_24.jpg deleted file mode 100644 index e021adfcc..000000000 Binary files a/resources/ui/units/vehicles/icons/Tunguska 2C6M_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/UAZ-469_24.jpg b/resources/ui/units/vehicles/icons/UAZ-469_24.jpg deleted file mode 100644 index 21d163920..000000000 Binary files a/resources/ui/units/vehicles/icons/UAZ-469_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Ural-375 ZU-23_24.jpg b/resources/ui/units/vehicles/icons/Ural-375 ZU-23_24.jpg deleted file mode 100644 index 57179b9d4..000000000 Binary files a/resources/ui/units/vehicles/icons/Ural-375 ZU-23_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Ural-375_24.jpg b/resources/ui/units/vehicles/icons/Ural-375_24.jpg deleted file mode 100644 index 13cb206f0..000000000 Binary files a/resources/ui/units/vehicles/icons/Ural-375_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Vulcan_24.jpg b/resources/ui/units/vehicles/icons/Vulcan_24.jpg deleted file mode 100644 index 25f0d35a1..000000000 Binary files a/resources/ui/units/vehicles/icons/Vulcan_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/Willys_MB_24.jpg b/resources/ui/units/vehicles/icons/Willys_MB_24.jpg deleted file mode 100644 index 705eb2e17..000000000 Binary files a/resources/ui/units/vehicles/icons/Willys_MB_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ZBD-04A_24.jpg b/resources/ui/units/vehicles/icons/ZBD-04A_24.jpg deleted file mode 100644 index 552ed3450..000000000 Binary files a/resources/ui/units/vehicles/icons/ZBD-04A_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ZSU-23-4 Shilka_24.jpg b/resources/ui/units/vehicles/icons/ZSU-23-4 Shilka_24.jpg deleted file mode 100644 index 334dc0655..000000000 Binary files a/resources/ui/units/vehicles/icons/ZSU-23-4 Shilka_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ZSU-57-2_24.jpg b/resources/ui/units/vehicles/icons/ZSU-57-2_24.jpg deleted file mode 100644 index e518ad961..000000000 Binary files a/resources/ui/units/vehicles/icons/ZSU-57-2_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ZU-23 Emplacement Closed_24.jpg b/resources/ui/units/vehicles/icons/ZU-23 Emplacement Closed_24.jpg deleted file mode 100644 index 4dbf6d311..000000000 Binary files a/resources/ui/units/vehicles/icons/ZU-23 Emplacement Closed_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/ZU-23_24.jpg b/resources/ui/units/vehicles/icons/ZU-23_24.jpg deleted file mode 100644 index 4dbf6d311..000000000 Binary files a/resources/ui/units/vehicles/icons/ZU-23_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/bofors40_24.jpg b/resources/ui/units/vehicles/icons/bofors40_24.jpg deleted file mode 100644 index dda787d8b..000000000 Binary files a/resources/ui/units/vehicles/icons/bofors40_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak18_24.jpg b/resources/ui/units/vehicles/icons/flak18_24.jpg deleted file mode 100644 index d8b4123b0..000000000 Binary files a/resources/ui/units/vehicles/icons/flak18_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak30_24.jpg b/resources/ui/units/vehicles/icons/flak30_24.jpg deleted file mode 100644 index 74cd7369b..000000000 Binary files a/resources/ui/units/vehicles/icons/flak30_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak36_24.jpg b/resources/ui/units/vehicles/icons/flak36_24.jpg deleted file mode 100644 index d039be18a..000000000 Binary files a/resources/ui/units/vehicles/icons/flak36_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak37_24.jpg b/resources/ui/units/vehicles/icons/flak37_24.jpg deleted file mode 100644 index b20089178..000000000 Binary files a/resources/ui/units/vehicles/icons/flak37_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak38_24.jpg b/resources/ui/units/vehicles/icons/flak38_24.jpg deleted file mode 100644 index f54c1d372..000000000 Binary files a/resources/ui/units/vehicles/icons/flak38_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/flak41_24.jpg b/resources/ui/units/vehicles/icons/flak41_24.jpg deleted file mode 100644 index 10f7efa1d..000000000 Binary files a/resources/ui/units/vehicles/icons/flak41_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/p-19 s-125 sr_24.jpg b/resources/ui/units/vehicles/icons/p-19 s-125 sr_24.jpg deleted file mode 100644 index 4630d5b2a..000000000 Binary files a/resources/ui/units/vehicles/icons/p-19 s-125 sr_24.jpg and /dev/null differ diff --git a/resources/ui/units/vehicles/icons/snr s-125 tr_24.jpg b/resources/ui/units/vehicles/icons/snr s-125 tr_24.jpg deleted file mode 100644 index 111d477c0..000000000 Binary files a/resources/ui/units/vehicles/icons/snr s-125 tr_24.jpg and /dev/null differ diff --git a/resources/ui/wizard/logo1.png b/resources/ui/wizard/logo1.png deleted file mode 100644 index 7aa676eee..000000000 Binary files a/resources/ui/wizard/logo1.png and /dev/null differ diff --git a/resources/ui/wizard/original/logo1.png b/resources/ui/wizard/original/logo1.png deleted file mode 100644 index 765e00bbb..000000000 Binary files a/resources/ui/wizard/original/logo1.png and /dev/null differ diff --git a/resources/ui/wizard/watermark1.png b/resources/ui/wizard/watermark1.png deleted file mode 100644 index 13dcfebb1..000000000 Binary files a/resources/ui/wizard/watermark1.png and /dev/null differ diff --git a/resources/ui/wizard/watermark2.png b/resources/ui/wizard/watermark2.png deleted file mode 100644 index d7c308d3d..000000000 Binary files a/resources/ui/wizard/watermark2.png and /dev/null differ diff --git a/resources/ui/wizard/watermark3.png b/resources/ui/wizard/watermark3.png deleted file mode 100644 index c30444f10..000000000 Binary files a/resources/ui/wizard/watermark3.png and /dev/null differ diff --git a/resources/units/aircraft/A-10A.yaml b/resources/units/aircraft/A-10A.yaml deleted file mode 100644 index e3b959f96..000000000 --- a/resources/units/aircraft/A-10A.yaml +++ /dev/null @@ -1,23 +0,0 @@ -always_keeps_gun: true -description: - The A-10A Thunderbolt II, also known as the Warthog, is a 'flying gun'. - The aircraft was used extensively during Operation Desert Storm, in support of NATO - operations in response to the Kosovo crisis, in Operation Enduring Freedom in Afghanistan - and in Operation Iraqi Freedom. The A-10A is a high-survivability and versatile - aircraft, popular with pilots for the 'get home' effectiveness.The mission of the - aircraft is ground attack against tanks, armored vehicles and installations, and - close air support of ground forces. The Warthog is famous for its massive 30mm cannon, - but it can also be armed with Maverick guided missiles and several types of bombs - and rockets. -introduced: 1977 -manufacturer: Fairchild Republic -origin: USA -price: 12 -role: Close Air Support/Attack -variants: - A-10A Thunderbolt II: {} -tasks: - BAI: 680 - CAS: 680 - OCA/Aircraft: 680 -hit_points: 32 diff --git a/resources/units/aircraft/A-10C.yaml b/resources/units/aircraft/A-10C.yaml deleted file mode 100644 index ee57dd8c2..000000000 --- a/resources/units/aircraft/A-10C.yaml +++ /dev/null @@ -1,33 +0,0 @@ -always_keeps_gun: true -description: - The A-10C Thunderbolt II, also known as the Warthog, is a 'flying gun'. The - A-10C is a high-survivability and versatile aircraft, popular with pilots for - the 'get home' effectiveness.The mission of the aircraft is ground attack - against tanks, armored vehicles and installations, and close air support of - ground forces. The Warthog is famous for its massive 30mm cannon, but it can - also be armed with Maverick guided missiles and several types of bombs and - rockets. -introduced: 2005 -manufacturer: Fairchild Republic -origin: USA -price: 18 -role: Close Air Support/Attack -variants: - A-10C Thunderbolt II (Suite 3): {} -radios: - # VHF for intraflight is not accepted anymore by DCS - # (see https://forums.eagle.ru/showthread.php?p=4499738). - intra_flight: AN/ARC-164 - inter_flight: AN/ARC-164 - channels: - type: common - namer: a10c-legacy - intra_flight_radio_index: 2 - inter_flight_radio_index: 2 -tasks: - BAI: 820 - CAS: 820 - OCA/Aircraft: 820 - OCA/Runway: 380 - Strike: 380 -hit_points: 32 diff --git a/resources/units/aircraft/A-10C_2.yaml b/resources/units/aircraft/A-10C_2.yaml deleted file mode 100644 index 757ba802e..000000000 --- a/resources/units/aircraft/A-10C_2.yaml +++ /dev/null @@ -1,37 +0,0 @@ -always_keeps_gun: true -description: - The A-10C Thunderbolt II, also known as the Warthog, is a 'flying gun'. The - A-10C is a high-survivability and versatile aircraft, popular with pilots for - the 'get home' effectiveness.The mission of the aircraft is ground attack - against tanks, armored vehicles and installations, and close air support of - ground forces. The Warthog is famous for its massive 30mm cannon, but it can - also be armed with Maverick guided missiles and several types of bombs and - rockets. -introduced: 2012 -manufacturer: Fairchild Republic -origin: USA -price: 20 -role: Close Air Support/Attack -variants: - A-10C Thunderbolt II (Suite 7): {} -radios: - # DCS will clobber channel 1 of the AN/ARC-164 with the flight's assigned - # frequency, so we may as well use that one for intra-flight. - # - # This ends up working out nicely anyway, because it's much easier on the - # pilot to have the AN/ARC-210 be the inter-flight radio since that's the one - # with HUD support and the control panel that makes switching channels easier. - intra_flight: AN/ARC-164 - inter_flight: AN/ARC-210 - channels: - type: common - namer: a10c-ii - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -tasks: - BAI: 830 - CAS: 830 - OCA/Aircraft: 830 - OCA/Runway: 390 - Strike: 390 -hit_points: 32 diff --git a/resources/units/aircraft/A-20G.yaml b/resources/units/aircraft/A-20G.yaml deleted file mode 100644 index f330ffb39..000000000 --- a/resources/units/aircraft/A-20G.yaml +++ /dev/null @@ -1,27 +0,0 @@ -always_keeps_gun: true -description: - The Douglas A-20 Havoc (company designation DB-7) is an American medium - bomber, attack aircraft, night intruder, night fighter, and reconnaissance aircraft - of World War II. Designed to meet an Army Air Corps requirement for a bomber, it - was ordered by France for their air force before the USAAC decided it would also - meet their requirements. French DB-7s were the first to see combat; after the fall - of France the bomber, under the service name Boston continued with the Royal Air - Force. From 1941, night fighter and intruder versions were given the service name - Havoc. In 1942 USAAF A-20s saw combat in North Africa. -introduced: 1943 -manufacturer: Douglas -origin: USA -price: 12 -role: Medium Bomber/Attack -variants: - A-20G Havoc: {} - Boston Mk.III: {} -tasks: - Anti-ship: 40 - BAI: 160 - CAS: 160 - DEAD: 170 - OCA/Aircraft: 160 - OCA/Runway: 140 - Strike: 140 -hit_points: 18 diff --git a/resources/units/aircraft/A-4E-C.yaml b/resources/units/aircraft/A-4E-C.yaml deleted file mode 100644 index 14609d4f0..000000000 --- a/resources/units/aircraft/A-4E-C.yaml +++ /dev/null @@ -1,31 +0,0 @@ -carrier_capable: true -description: - The Skyhawk is a relatively lightweight aircraft, with a maximum takeoff - weight of 24,500 pounds (11,100 kg), and has a top speed of 670 miles per hour (1,080 - km/h). The aircraft's five hardpoints support a variety of missiles, bombs, and - other munitions. Skyhawks played key roles in the Vietnam War, the Yom Kippur War, - and the Falklands War. Sixty years after the aircraft's first flight in 1954, some - of the 2,960 produced (through February 1979)[1] remain in service with the Argentine - Air Force and the Brazilian Naval Aviation. -introduced: 1962 -manufacturer: Douglas -origin: USA -price: 7 -role: Carrier-based Attack/Light Fighter -gunfighter: true -variants: - A-4E Skyhawk: {} -tasks: - BAI: 660 - BARCAP: 160 - CAS: 660 - DEAD: 390 - Escort: 160 - Fighter sweep: 160 - Intercept: 160 - OCA/Aircraft: 660 - OCA/Runway: 360 - SEAD: 110 - SEAD Escort: 110 - Strike: 360 - TARCAP: 160 diff --git a/resources/units/aircraft/A-50.yaml b/resources/units/aircraft/A-50.yaml deleted file mode 100644 index fffab1b88..000000000 --- a/resources/units/aircraft/A-50.yaml +++ /dev/null @@ -1,11 +0,0 @@ -description: The A-50 is an AWACS plane. -max_group_size: 1 -max_range: 2000 -price: 50 -patrol: - altitude: 33000 -variants: - A-50: null -tasks: - AEW&C: 10 -hit_points: 60 diff --git a/resources/units/aircraft/AH-1W.yaml b/resources/units/aircraft/AH-1W.yaml deleted file mode 100644 index b388d3f3d..000000000 --- a/resources/units/aircraft/AH-1W.yaml +++ /dev/null @@ -1,26 +0,0 @@ -class: Helicopter -always_keeps_gun: true -carrier_capable: true -cabin_size: 0 # Can not transport troops -can_carry_crates: false # Can not carry crates -description: - The AH-1 Cobra was developed in the mid-1960s as an interim gunship for - the U.S. Army for use during the Vietnam War. The Cobra shared the proven transmission, - rotor system, and the T53 turboshaft engine of the UH-1 'Huey'. By June 1967, the - first AH-1G HueyCobras had been delivered. Bell built 1,116 AH-1Gs for the U.S. - Army between 1967 and 1973, and the Cobras chalked up over a million operational - hours in Vietnam. -introduced: 1986 -lha_capable: true -manufacturer: Bell -origin: USA -price: 14 -role: Attack -variants: - AH-1J SeaCobra: {} - AH-1W SuperCobra: {} -tasks: - BAI: 480 - CAS: 480 - OCA/Aircraft: 480 -hit_points: 14 diff --git a/resources/units/aircraft/AH-64A.yaml b/resources/units/aircraft/AH-64A.yaml deleted file mode 100644 index d55397b74..000000000 --- a/resources/units/aircraft/AH-64A.yaml +++ /dev/null @@ -1,27 +0,0 @@ -class: Helicopter -always_keeps_gun: true -cabin_size: 0 # Can not transport troops -can_carry_crates: false # Can not carry crates -description: - The legendary 'Apache' is an US twin-turboshaft attack helicopter for - a crew of two. It features a nose-mounted sensor suite for target acquisition and - night vision systems. It is armed with a 30 mm (1.18 in) M230 chain gun carried - between the main landing gear, under the aircraft's forward fuselage, and four hardpoints - mounted on stub-wing pylons for carrying armament and stores, typically a mixture - of AGM-114 Hellfire missiles and Hydra 70 rocket pods. The AH-64 has significant - systems redundancy to improve combat survivability. American AH-64s have served - in conflicts in Panama, the Persian Gulf, Kosovo, Afghanistan, and Iraq. Israel - used the Apache in its military conflicts in Lebanon and the Gaza Strip. British - and Dutch Apaches have seen deployments in wars in Afghanistan and Iraq. -introduced: 1986 -manufacturer: Boeing -origin: USA -price: 16 -role: Attack -variants: - AH-64A Apache: {} -tasks: - BAI: 490 - CAS: 490 - OCA/Aircraft: 490 -hit_points: 14 diff --git a/resources/units/aircraft/AH-64D.yaml b/resources/units/aircraft/AH-64D.yaml deleted file mode 100644 index 8a87db991..000000000 --- a/resources/units/aircraft/AH-64D.yaml +++ /dev/null @@ -1,28 +0,0 @@ -class: Helicopter -always_keeps_gun: true -lha_capable: true -cabin_size: 0 # Can not transport troops -can_carry_crates: false # Can not carry crates -description: - The legendary 'Apache' is an US twin-turboshaft attack helicopter for - a crew of two. It features a nose-mounted sensor suite for target acquisition and - night vision systems. It is armed with a 30 mm (1.18 in) M230 chain gun carried - between the main landing gear, under the aircraft's forward fuselage, and four hardpoints - mounted on stub-wing pylons for carrying armament and stores, typically a mixture - of AGM-114 Hellfire missiles and Hydra 70 rocket pods. The AH-64 has significant - systems redundancy to improve combat survivability. American AH-64s have served - in conflicts in Panama, the Persian Gulf, Kosovo, Afghanistan, and Iraq. Israel - used the Apache in its military conflicts in Lebanon and the Gaza Strip. British - and Dutch Apaches have seen deployments in wars in Afghanistan and Iraq. -introduced: 2003 -manufacturer: Boeing -origin: USA -price: 20 -role: Attack -variants: - AH-64D Apache Longbow (AI): {} -tasks: - BAI: 500 - CAS: 500 - OCA/Aircraft: 500 -hit_points: 14 diff --git a/resources/units/aircraft/AH-64D_BLK_II.yaml b/resources/units/aircraft/AH-64D_BLK_II.yaml deleted file mode 100644 index 3a7bcbc86..000000000 --- a/resources/units/aircraft/AH-64D_BLK_II.yaml +++ /dev/null @@ -1,43 +0,0 @@ -class: Helicopter -always_keeps_gun: true -lha_capable: true -cabin_size: 0 # Can not transport troops -can_carry_crates: false # Can not carry crates -description: - The legendary 'Apache' is an US twin-turboshaft attack helicopter for - a crew of two. It features a nose-mounted sensor suite for target acquisition and - night vision systems. It is armed with a 30 mm (1.18 in) M230 chain gun carried - between the main landing gear, under the aircraft's forward fuselage, and four hardpoints - mounted on stub-wing pylons for carrying armament and stores, typically a mixture - of AGM-114 Hellfire missiles and Hydra 70 rocket pods. The AH-64 has significant - systems redundancy to improve combat survivability. American AH-64s have served - in conflicts in Panama, the Persian Gulf, Kosovo, Afghanistan, and Iraq. Israel - used the Apache in its military conflicts in Lebanon and the Gaza Strip. British - and Dutch Apaches have seen deployments in wars in Afghanistan and Iraq. -introduced: 2003 -manufacturer: Boeing -origin: USA -price: 20 -role: Attack -cruise_speed_kt_indicated: 120 -variants: - AH-64D Apache Longbow: {} -radios: - # DCS uses the 2nd Radio AN/ARC-164 (UHF) as the main intra flight for the Apache - # so we use this Radio for Intra and Inter Flight for now - # The radio frequencies set in the mission editor are in the current state of Early - # access not used for radio presets. Only the flight frequency is used. Any other - # frequency has to be entered manually atm. - intra_flight: AN/ARC-164 - inter_flight: AN/ARC-164 - channels: - type: common - namer: apache - intra_flight_radio_index: 2 - inter_flight_radio_index: 2 -tasks: - BAI: 510 - CAS: 510 - DEAD: 115 - OCA/Aircraft: 510 -hit_points: 20 diff --git a/resources/units/aircraft/AJS37.yaml b/resources/units/aircraft/AJS37.yaml deleted file mode 100644 index 63a53a01b..000000000 --- a/resources/units/aircraft/AJS37.yaml +++ /dev/null @@ -1,46 +0,0 @@ -description: - "The AJS-37 Viggen is a Swedish double-delta supersonic attack aircraft\ - \ from the late Cold War. It was the backbone of the Swedish Air Force during the\ - \ Cold war, serving as the main attack and anti-ship platform. The AJS is the 90\u2019\ - s upgrade of this 70's era aircraft, adding several advanced weapons and systems\ - \ functionalities. The aircraft was designed around the pilot, with an excellent\ - \ man-machine interface, supporting the pilot through the smart use of autopilot\ - \ systems, radar and HUD symbology in order to deliver the ordnance onto targets\ - \ from treetop level with high speed attack runs.\n\nThe aircraft is armed with\ - \ multiple weapon systems ranging from programmable stand-off weapons such as the\ - \ RB-15F antiship missile to the BK90 Cluster munitions dispenser to various bombs,\ - \ rockets and missiles for a wide range of target types. The aircraft can also carry\ - \ gun pods and the Sidewinder series of infrared-guided missiles for air defence\ - \ and self-protection purposes." -introduced: 1993 -manufacturer: Saab -origin: Sweden -price: 15 -role: Attack/Reconnaissance -variants: - AJS-37 Viggen: {} -radios: - # The AJS37 has somewhat unique radio configuration. Two backup radio - # (FR 24) can only operate simultaneously with the main radio in guard - # mode. As such, we only use the main radio for both inter- and intra- - # flight communication. - intra_flight: FR 22 - inter_flight: FR 22 - channels: - type: viggen - namer: viggen -kneeboard_units: "metric" -# default_overrides: -# MissionGeneratorSetting: 0 -# Rb04GroupTarget: 3 -# Rb04VinkelHopp: 0 -# WeapSafeHeight: 1 -tasks: - Anti-ship: 190 - BAI: 620 - CAS: 620 - DEAD: 270 - OCA/Aircraft: 620 - OCA/Runway: 620 - Strike: 630 -hit_points: 18 diff --git a/resources/units/aircraft/AV8BNA.yaml b/resources/units/aircraft/AV8BNA.yaml deleted file mode 100644 index ed45d5104..000000000 --- a/resources/units/aircraft/AV8BNA.yaml +++ /dev/null @@ -1,66 +0,0 @@ -carrier_capable: true -description: - 'The AV-8B project was born in the early 1970''s as an effort to address - the operational inadequacies of the AV-8A first generation Harrier, aimed to dramatically - improve the capabilities and performance of the early AV-8A''s. The AV-8B made its - maiden flight in November 1981 and entered service with the United States Marine - Corps in January 1985. It later evolved into the AV-8B N/A (Night Attack) and AV-8B - Harrier II Plus. - - - First flight of a modified AV-8B in the night attack configuration was on June 26th, - 1987. Deliveries to the USMC began in September of 1989 to VMA-214 at Yuma, Arizona. - Follow-up units based out of Yuma received their Night Attack AV-8Bs by the end - of 1992.The AV-8B N/A variant (originally known as the AV-8D) had its first operational - development in 1984 and included use of the NAVFLIR (Navigation Forward-Looking - Infrared camera, consisting of a GEC-Marconi FLIR system mounted in the nose) for - night operations. Additionally, GEC Cat''s Eyes night vision goggles were provided - to the pilot as well as a revised cockpit with color MFDs, a wider field-of-view - HUD display, a color CRT digital moving map, and a complete "heads-down" operation - capability. The AV-8B N/A also sports four Tracor ALE-39 countermeasures dispensers - along the top of the rear fuselage, in addition to two ALE-39 dispensers along the - lower rear of the fuselage. The AV-8B N/A also fields an updated version of the - Rolls-Royce Pegasus 11-61 (F402-RR-408) vectored-thrust turbofan engine.' -introduced: 1989 -lha_capable: true -manufacturer: McDonnell Douglas -origin: USA/UK -price: 15 -role: V/STOL Attack -max_range: 100 -variants: - AV-8B Harrier II Night Attack: {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -# default_overrides: -# AAR_Zone1: 0 -# AAR_Zone2: 0 -# AAR_Zone3: 0 -# ClockTime: 1 -# EWDispenserBL: 2 -# EWDispenserBR: 2 -# EWDispenserTBL: 2 -# EWDispenserTBR: 2 -# EWDispenserTFL: 1 -# EWDispenserTFR: 1 -# LaserCode1: 8 -# LaserCode10: 8 -# LaserCode100: 6 -# MountNVG: false -# RocketBurst: 1 -tasks: - Anti-ship: 60 - BAI: 690 - CAS: 690 - DEAD: 350 - OCA/Aircraft: 690 - OCA/Runway: 590 - SEAD: 70 - SEAD Escort: 70 - Strike: 590 -hit_points: 18 diff --git a/resources/units/aircraft/An-26B.yaml b/resources/units/aircraft/An-26B.yaml deleted file mode 100644 index 856a76377..000000000 --- a/resources/units/aircraft/An-26B.yaml +++ /dev/null @@ -1,8 +0,0 @@ -description: The An-26B is a military transport aircraft. -price: 15 -max_range: 800 -variants: - An-26B: null -tasks: - Transport: 110 -hit_points: 45 diff --git a/resources/units/aircraft/An-30M.yaml b/resources/units/aircraft/An-30M.yaml deleted file mode 100644 index e9c1e669c..000000000 --- a/resources/units/aircraft/An-30M.yaml +++ /dev/null @@ -1,6 +0,0 @@ -description: The An-30M is a military transport aircraft. -price: 15 -variants: - An-30M: null -tasks: {} -hit_points: 45 diff --git a/resources/units/aircraft/B-17G.yaml b/resources/units/aircraft/B-17G.yaml deleted file mode 100644 index 434aa43c0..000000000 --- a/resources/units/aircraft/B-17G.yaml +++ /dev/null @@ -1,26 +0,0 @@ -description: - The B-17 was primarily employed by the USAAF in the daylight strategic - bombing campaign of World War II against German industrial, military and civilian - targets. The United States Eighth Air Force, based at many airfields in central, - eastern and southern England, and the Fifteenth Air Force, based in Italy, complemented - the RAF Bomber Command's night-time area bombing in the Combined Bomber Offensive - to help secure air superiority over the cities, factories and battlefields of Western - Europe in preparation for the invasion of France in 1944.it was a relatively fast, - high-flying, long-range bomber with heavy defensive armament at the expense of bombload. - It developed a reputation for toughness based upon stories and photos of badly damaged - B-17s safely returning to base. The B-17 dropped more bombs than any other U.S. - aircraft in World War II. Of approximately 1.5 million tons of bombs dropped on - Nazi Germany and its occupied territories by U.S. aircraft, over 640,000 tons were - dropped from B-17s. -introduced: 1943 -manufacturer: Boeing -origin: USA -price: 16 -role: Heavy Bomber -variants: - B-17G Flying Fortress: {} - Fortress Mk.III: {} -tasks: - OCA/Runway: 150 - Strike: 150 -hit_points: 18 diff --git a/resources/units/aircraft/B-1B.yaml b/resources/units/aircraft/B-1B.yaml deleted file mode 100644 index c38fd69a2..000000000 --- a/resources/units/aircraft/B-1B.yaml +++ /dev/null @@ -1,26 +0,0 @@ -description: - The Rockwell B-1 Lancer is a supersonic variable-sweep wing, heavy bomber - used by the United States Air Force. It is commonly called the 'Bone' (from 'B-One').It - is one of three strategic bombers in the U.S. Air Force fleet as of 2021, the other - two being the B-2 Spirit and the B-52 Stratofortress. It first served in combat - during Operation Desert Fox in 1998 and again during the NATO action in Kosovo the - following year. The B-1B has supported U.S. and NATO military forces in Afghanistan - and Iraq. The Air Force had 62 B-1Bs in service as of 2016. The Northrop Grumman - B-21 Raider is to begin replacing the B-1B after 2025; all B-1s are planned to be - retired by 2036. -introduced: 1986 -manufacturer: Rockwell -origin: USA -price: 45 -role: Supersonic Strategic Bomber -max_range: 2000 -variants: - B-1B Lancer: {} -tasks: - BAI: 670 - CAS: 670 - DEAD: 220 - OCA/Aircraft: 670 - OCA/Runway: 670 - Strike: 700 -hit_points: 60 diff --git a/resources/units/aircraft/B-52H.yaml b/resources/units/aircraft/B-52H.yaml deleted file mode 100644 index 7eda60a0e..000000000 --- a/resources/units/aircraft/B-52H.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: - The Boeing B-52 Stratofortress is capable of carrying up to 70,000 pounds - (32,000 kg) of weapons, and has a typical combat range of more than 8,800 miles - (14,080 km) without aerial refueling. The B-52 completed sixty years of continuous - service with its original operator in 2015. After being upgraded between 2013 and - 2015, the last airplanes are expected to serve into the 2050s. -introduced: 1961 -manufacturer: Boeing -origin: USA -price: 35 -role: Strategic Bomber -max_range: 2000 -variants: - B-52H Stratofortress: {} -tasks: - Anti-ship: 100 - DEAD: 210 - OCA/Runway: 660 - Strike: 690 -hit_points: 60 diff --git a/resources/units/aircraft/Bf-109K-4.yaml b/resources/units/aircraft/Bf-109K-4.yaml deleted file mode 100644 index 747cb7f81..000000000 --- a/resources/units/aircraft/Bf-109K-4.yaml +++ /dev/null @@ -1,37 +0,0 @@ -always_keeps_gun: true -description: - The BF 109 series was, along with the Focke-Wulf Fw 190, the backbone of the - Luftwaffe's fighter force. The Bf 109 first saw operational service in 1937 - during the Spanish Civil War and was still in service at the dawn of the jet - age at the end of World War II in 1945. The final production version of the Bf - 109 was the K series or Kurfürst, introduced in late 1944, powered by the DB - 605D engine with up to 2,000 PS (1,973 HP). Though externally akin to the late - production Bf 109G series, a large number of internal changes and aerodynamic - improvements were incorporated that improved its effectiveness and remedied - flaws, keeping it competitive with the latest Allied and Soviet fighters. The - Bf 109's outstanding rate of climb was superior to many Allied adversaries - including the P-51D Mustang, Spitfire Mk. XIV and Hawker Tempest Mk. V. -introduced: 1944 -manufacturer: Messerschmitt -price: 4 -role: Fighter -gunfighter: true -variants: - "Bf 109 K-4 Kurfürst": {} -kneeboard_units: "metric" -# default_overrides: -# Flare_Gun: 1 -# MW50TankContents: 1 -tasks: - BAI: 50 - BARCAP: 60 - CAS: 50 - DEAD: 20 - Escort: 60 - Fighter sweep: 60 - Intercept: 60 - OCA/Aircraft: 50 - OCA/Runway: 20 - Strike: 20 - TARCAP: 60 -hit_points: 18 diff --git a/resources/units/aircraft/Bronco-OV-10A.yaml b/resources/units/aircraft/Bronco-OV-10A.yaml deleted file mode 100644 index fd45b7992..000000000 --- a/resources/units/aircraft/Bronco-OV-10A.yaml +++ /dev/null @@ -1,22 +0,0 @@ -carrier_capable: false -description: - The North American Rockwell OV-10 Bronco is an American twin-turboprop - light attack and observation aircraft. It was developed in the 1960s as a special aircraft - for counter-insurgency (COIN) combat, and one of its primary missions was as a forward air control (FAC) aircraft. - It can carry up to 3,200 lb (1,450 kg) of external munitions and internal loads such as paratroopers or stretchers, - and can loiter for three or more hours. -introduced: 1969 -manufacturer: North American Rockwell -origin: USA -price: 4 -role: COIN / FAC /Light Attack -gunfighter: true -variants: - OV-10A Bronco: {} -tasks: - BAI: 650 - CAS: 650 - DEAD: 60 - OCA/Aircraft: 650 - OCA/Runway: 330 - Strike: 330 diff --git a/resources/units/aircraft/C-101CC.yaml b/resources/units/aircraft/C-101CC.yaml deleted file mode 100644 index 82fa3ff92..000000000 --- a/resources/units/aircraft/C-101CC.yaml +++ /dev/null @@ -1,33 +0,0 @@ -description: - The C-101CC Aviojet, with its 7 hard-points and uprated engine, is a - versatile light attack aircraft that has seen combat with the Honduras Air Force - against drug traffickers. It is also in service with the Jordanian and Chilean air - forces. -introduced: 1980 -manufacturer: CASA -origin: Spain -price: 8 -role: Light Attack -gunfighter: true -variants: - C-101CC Aviojet: {} -# default_overrides: -# CameraRecorder: false -# MountIFRHood: false -# NS430allow: 1 -# NetCrewControlPriority: 1 -# SightSunFilter: false -# SoloFlight: false -tasks: - Anti-ship: 10 - BAI: 230 - BARCAP: 130 - CAS: 230 - Escort: 130 - Fighter sweep: 130 - Intercept: 130 - OCA/Aircraft: 230 - OCA/Runway: 170 - Strike: 170 - TARCAP: 130 -hit_points: 18 diff --git a/resources/units/aircraft/C-130.yaml b/resources/units/aircraft/C-130.yaml deleted file mode 100644 index d9e9f7a87..000000000 --- a/resources/units/aircraft/C-130.yaml +++ /dev/null @@ -1,8 +0,0 @@ -description: The C-130 is a military transport aircraft. -price: 15 -max_range: 1000 -variants: - C-130: null -tasks: - Transport: 130 -hit_points: 45 diff --git a/resources/units/aircraft/C-17A.yaml b/resources/units/aircraft/C-17A.yaml deleted file mode 100644 index c0ea31979..000000000 --- a/resources/units/aircraft/C-17A.yaml +++ /dev/null @@ -1,8 +0,0 @@ -description: The C-17 is a military transport aircraft. -price: 18 -max_range: 2000 -variants: - C-17A: null -tasks: - Transport: 150 -hit_points: 45 diff --git a/resources/units/aircraft/C-47.yaml b/resources/units/aircraft/C-47.yaml deleted file mode 100644 index e97f81fcc..000000000 --- a/resources/units/aircraft/C-47.yaml +++ /dev/null @@ -1,16 +0,0 @@ -description: - The C-47 is a military transport aircraft developed from the civilian Douglas DC-3 airliner. - It was used extensively by the Allies during World War II and remained in front-line service with - various military operators for many years. -introduced: 1942 -manufacturer: Douglas -origin: USA -role: Transport -price: 6 -max_range: 800 -variants: - C-47 Skytrain: null - C-47 Dakota: null -tasks: - Transport: 90 -hit_points: 18 diff --git a/resources/units/aircraft/CH-47D.yaml b/resources/units/aircraft/CH-47D.yaml deleted file mode 100644 index c8cff22b6..000000000 --- a/resources/units/aircraft/CH-47D.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Helicopter -carrier_capable: true -lha_capable: true -cabin_size: 24 # It should have 33 but we do not want so much for CTLD to be possible -can_carry_crates: true -description: The CH-47D is a transport helicopter. -price: 6 -variants: - CH-47D: null -tasks: - Air Assault: 90 - Transport: 70 -hit_points: 20 diff --git a/resources/units/aircraft/CH-53E.yaml b/resources/units/aircraft/CH-53E.yaml deleted file mode 100644 index f587a4cbf..000000000 --- a/resources/units/aircraft/CH-53E.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Helicopter -carrier_capable: true -lha_capable: true -cabin_size: 24 # It should have 37 but we do not want so much for CTLD to be possible -can_carry_crates: true -description: The CH-53 is a military transport helicopter. -price: 6 -variants: - CH-53E: null -tasks: - Air Assault: 100 - Transport: 80 -hit_points: 20 diff --git a/resources/units/aircraft/E-2C.yaml b/resources/units/aircraft/E-2C.yaml deleted file mode 100644 index 22bef9c3d..000000000 --- a/resources/units/aircraft/E-2C.yaml +++ /dev/null @@ -1,19 +0,0 @@ -carrier_capable: true -max_group_size: 1 -description: - The Northrop Grumman E-2 Hawkeye is an American all-weather, carrier-capable - tactical airborne early warning (AEW) aircraft. -introduced: 1973 -manufacturer: Northrop Grumman -origin: USA -price: 50 -role: AEW&C -max_range: 2000 -patrol: - altitude: 30000 -variants: - E-2C Hawkeye: {} - E-2D Advanced Hawkeye: {} -tasks: - AEW&C: 20 -hit_points: 25 diff --git a/resources/units/aircraft/E-3A.yaml b/resources/units/aircraft/E-3A.yaml deleted file mode 100644 index c0c466c56..000000000 --- a/resources/units/aircraft/E-3A.yaml +++ /dev/null @@ -1,11 +0,0 @@ -description: The E-3A is a AWACS aicraft. -price: 50 -max_group_size: 1 -max_range: 2000 -patrol: - altitude: 35000 -variants: - E-3A: null -tasks: - AEW&C: 30 -hit_points: 60 diff --git a/resources/units/aircraft/EA-18G.yaml b/resources/units/aircraft/EA-18G.yaml deleted file mode 100644 index 797310171..000000000 --- a/resources/units/aircraft/EA-18G.yaml +++ /dev/null @@ -1,41 +0,0 @@ -carrier_capable: true -description: - "The Boeing EA-18G Growler is an American carrier-based electronic warfare aircraft, - a specialized version of the two-seat F/A-18F Super Hornet. The EA-18G replaced the - Northrop Grumman EA-6B Prowlers in service with the United States Navy." -introduced: 1999 -manufacturer: McDonnell Douglas -origin: USA -price: 25 -role: Carrier-based Multirole Fighter -fuel: - # Parking A1 to RWY 32 at Akrotiri. - taxi: 170 - # AB takeoff to 350/0.85, reduce to MIL and maintain 350 to 25k ft. - climb_ppm: 44.25 - # 0.85 mach for 100NM. - cruise_ppm: 22.1 - # ~0.9 mach for 100NM. Occasional AB use. - combat_ppm: 27.5 - min_safe: 2000 -variants: - EA-18G Growler: {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - # DCS will clobber channel 1 of the first radio compatible with the flight's - # assigned frequency. Since the F/A-18's two radios are both AN/ARC-210s, - # radio 1 will be compatible regardless of which frequency is assigned, so - # we must use radio 1 for the intra-flight radio. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -utc_kneeboard: true -# default_overrides: -# HelmetMountedDevice: 1 -# InnerBoard: 0 -# OuterBoard: 0 -tasks: - DEAD: 500 - SEAD: 600 diff --git a/resources/units/aircraft/EA-18G_growler.yaml b/resources/units/aircraft/EA-18G_growler.yaml deleted file mode 100644 index 51711b653..000000000 --- a/resources/units/aircraft/EA-18G_growler.yaml +++ /dev/null @@ -1,47 +0,0 @@ -carrier_capable: true -description: - 'The EA-18G Growler is twin engine, supersonic Electronic Warfare Aircraft that is flown - by a pilot and a WSO (Weapon Systems Officer) in a "glass cockpit". It combines extreme maneuverability , a - deadly arsenal of weapons, and the ability to operate from an aircraft carrier. - Operated by several nations, this multi-role fighter has been instrumental in conflicts - from 2009 to today. - - The flight capabilities of the Growler closely mirror those of the F/A-18E/F. - This characteristic allows the Growler to excel in both escort jamming and the conventional standoff jamming mission, - which involves radar jamming and deception. Growlers can seamlessly accompany F/A-18s throughout - all stages of an attack mission. To enhance the Growler's stability during electronic warfare operations, - Boeing made modifications to the leading edge fairings and wing fold hinge fairings, incorporating wing fences and - aileron "tripper strips".' - -introduced: 1999 -manufacturer: Boeing Defense, Space & Security -origin: USA -price: 32 -role: Carrier-based Electronic Warfare Aircraft - -default_livery: "VAQ-139" -fuel: - -variants: - -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - # DCS will clobber channel 1 of the first radio compatible with the flight's - # assigned frequency. Since the EA-18's two radios are both AN/ARC-210s, - # radio 1 will be compatible regardless of which frequency is assigned, so - # we must use radio 1 for the intra-flight radio. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -utc_kneeboard: true -# default_overrides: -# HelmetMountedDevice: 1 -# InnerBoard: 0 -# OuterBoard: 0 -tasks: - DEAD: 600 - SEAD: 500 - SEAD Escort: 500 -hit_points: 20 diff --git a/resources/units/aircraft/F-117A.yaml b/resources/units/aircraft/F-117A.yaml deleted file mode 100644 index a4d3a32ad..000000000 --- a/resources/units/aircraft/F-117A.yaml +++ /dev/null @@ -1,23 +0,0 @@ -description: - The Lockheed F-117 Nighthawk is a semi-retired American single-seat, - twin-engine stealth attack aircraft that was developed by Lockheed's secretive Skunk - Works division and operated by the United States Air Force (USAF). It was the first - operational aircraft to be designed around stealth technology. The F-117 was widely - publicized for its role in the Persian Gulf War of 1991. Although it was commonly - referred to as the 'Stealth Fighter', it was strictly a ground-attack aircraft. - F-117s took part in the conflict in Yugoslavia, where one was shot down and another - damaged by surface-to-air missiles (SAM) in 1999. The U.S. Air Force retired the - F-117 in April 2008, primarily due to the fielding of the F-22 Raptor. Despite the - type's retirement, a portion of the fleet has been kept in airworthy condition, - and Nighthawks have been observed flying in 2020. -introduced: 1983 -manufacturer: Lockheed -origin: USA -price: 35 -role: Stealth Attack -variants: - F-117A Nighthawk: {} -tasks: - Strike: 710 -has_built_in_target_pod: true -hit_points: 20 diff --git a/resources/units/aircraft/F-14A-135-GR.yaml b/resources/units/aircraft/F-14A-135-GR.yaml deleted file mode 100644 index d798942f0..000000000 --- a/resources/units/aircraft/F-14A-135-GR.yaml +++ /dev/null @@ -1,62 +0,0 @@ -carrier_capable: true -description: - "The Grumman F-14 Tomcat is a two-crew, variable wing-geometry, maritime\ - \ air superiority fighter that served with the US Navy for 32 years and continues\ - \ to serve with the IRIAF in Iran. The F-14 was the US Navy's frontline fighter\ - \ from the 1970s to the mid-2000s. Over the course of its long service it also became\ - \ one of the US Navy\u2019s premier precision ground-attack platform and its lone\ - \ airborne reconnaissance asset.\n\nNoteworthy features of the Tomcat are its swing-wing\ - \ configuration, two-man crew, and the powerful AN/AWG-9 Weapons Control System\ - \ (WCS) and radar. The AWG-9 allows employment of the long-range AIM-54 Phoenix\ - \ air-to-air missile, and the LANTIRN targeting pod allows precision ground strikes\ - \ using laser-guided bombs. The F-14 Tomcat was present in several historic events\ - \ that include the two Gulf of Sidra incidents, Operations Desert Storm Iraqi Freedom,\ - \ the Yugoslavian conflict, and Operation Enduring Freedom over Afghanistan. It\ - \ was also immortalized in the iconic motion picture, Top Gun, and starred in several\ - \ other feature films including The Final Countdown, Executive Decision, and others.\n\ - \nThe Tomcat was also played a vital role in the Iran-Iraq war of the 1980s, where\ - \ is flew for the Islamic Republic of Iran Air Force." -introduced: 1984 -manufacturer: Grumman -origin: USA -price: 22 -role: Carrier-based Air-Superiority Fighter/Fighter Bomber -max_range: 350 -variants: - F-14A Tomcat (Block 135-GR Late): {} -radios: - intra_flight: AN/ARC-182 - inter_flight: AN/ARC-159 - channels: - type: common - namer: tomcat - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -default_overrides: - INSAlignmentStored: true -# ALE39Loadout: 0 -# IlsChannel: 1 -# KY28Key: 1 -# LGB1: 8 -# LGB10: 8 -# LGB100: 6 -# LGB1000: 1 -# M61BURST: 0 -# TacanBand: 0 -# TacanChannel: 0 -# UseLAU138: true -tasks: - BAI: 630 - BARCAP: 520 - CAS: 630 - DEAD: 240 - Escort: 520 - Fighter sweep: 520 - Intercept: 520 - OCA/Aircraft: 630 - OCA/Runway: 550 - SEAD: 90 - SEAD Escort: 90 - Strike: 550 - TARCAP: 520 -hit_points: 20 diff --git a/resources/units/aircraft/F-14B.yaml b/resources/units/aircraft/F-14B.yaml deleted file mode 100644 index c622e3690..000000000 --- a/resources/units/aircraft/F-14B.yaml +++ /dev/null @@ -1,62 +0,0 @@ -carrier_capable: true -description: - "The Grumman F-14 Tomcat is a two-crew, variable wing-geometry, maritime\ - \ air superiority fighter that served with the US Navy for 32 years and continues\ - \ to serve with the IRIAF in Iran. The F-14 was the US Navy's frontline fighter\ - \ from the 1970s to the mid-2000s. Over the course of its long service it also became\ - \ one of the US Navy\u2019s premier precision ground-attack platform and its lone\ - \ airborne reconnaissance asset.\n\nNoteworthy features of the Tomcat are its swing-wing\ - \ configuration, two-man crew, and the powerful AN/AWG-9 Weapons Control System\ - \ (WCS) and radar. The AWG-9 allows employment of the long-range AIM-54 Phoenix\ - \ air-to-air missile, and the LANTIRN targeting pod allows precision ground strikes\ - \ using laser-guided bombs. The F-14 Tomcat was present in several historic events\ - \ that include the two Gulf of Sidra incidents, Operations Desert Storm Iraqi Freedom,\ - \ the Yugoslavian conflict, and Operation Enduring Freedom over Afghanistan. It\ - \ was also immortalized in the iconic motion picture, Top Gun, and starred in several\ - \ other feature films including The Final Countdown, Executive Decision, and others.\n\ - \nThe Tomcat was also played a vital role in the Iran-Iraq war of the 1980s, where\ - \ is flew for the Islamic Republic of Iran Air Force." -introduced: 1987 -manufacturer: Grumman -origin: USA -price: 26 -role: Carrier-based Air-Superiority Fighter/Fighter Bomber -max_range: 350 -variants: - F-14B Tomcat: {} -radios: - intra_flight: AN/ARC-182 - inter_flight: AN/ARC-159 - channels: - type: common - namer: tomcat - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -default_overrides: - INSAlignmentStored: true -# ALE39Loadout: 0 -# IlsChannel: 1 -# KY28Key: 1 -# LGB1: 8 -# LGB10: 8 -# LGB100: 6 -# LGB1000: 1 -# M61BURST: 0 -# TacanBand: 0 -# TacanChannel: 0 -# UseLAU138: true -tasks: - BAI: 640 - BARCAP: 530 - CAS: 640 - DEAD: 250 - Escort: 530 - Fighter sweep: 530 - Intercept: 530 - OCA/Aircraft: 640 - OCA/Runway: 560 - SEAD: 100 - SEAD Escort: 100 - Strike: 560 - TARCAP: 530 -hit_points: 20 diff --git a/resources/units/aircraft/F-15C.yaml b/resources/units/aircraft/F-15C.yaml deleted file mode 100644 index 2b163ddff..000000000 --- a/resources/units/aircraft/F-15C.yaml +++ /dev/null @@ -1,21 +0,0 @@ -description: - The F-15 has often been labeled as the greatest U.S. fighter aircraft - from the 1970s until the early 21st century. The F-15C is a pure fighter with outstanding - performance and has scored over 100 air-to-air victories without suffering any confirmed - losses. -introduced: 1978 -manufacturer: McDonnell Douglas -origin: USA -price: 20 -role: Air-Superiority Fighter -max_range: 400 -variants: - F-15C Eagle: {} - F-15J Eagle: {} -tasks: - BARCAP: 540 - Escort: 540 - Fighter sweep: 540 - Intercept: 540 - TARCAP: 540 -hit_points: 20 diff --git a/resources/units/aircraft/F-15E.yaml b/resources/units/aircraft/F-15E.yaml deleted file mode 100644 index 801aba100..000000000 --- a/resources/units/aircraft/F-15E.yaml +++ /dev/null @@ -1,28 +0,0 @@ -description: - The F-15 has often been labeled as the greatest U.S. fighter aircraft from the - 1970s until the early 21st century. The F-15E is a multirole fighter and - exceeds in CAS operations. It served worldwide without suffering any confirmed - losses. -introduced: 1988 -manufacturer: McDonnell Douglas -origin: USA -price: 24 -role: Multirole Strike Fighter -max_range: 300 -variants: - F-15E Strike Eagle: - display_name: F-15E Strike Eagle (AI) -tasks: - BAI: 760 - BARCAP: 240 - CAS: 760 - DEAD: 260 - Escort: 240 - Fighter sweep: 240 - Intercept: 240 - OCA/Aircraft: 760 - OCA/Runway: 630 - Strike: 640 - TARCAP: 240 -has_built_in_target_pod: true -hit_points: 20 diff --git a/resources/units/aircraft/F-15ESE.yaml b/resources/units/aircraft/F-15ESE.yaml deleted file mode 100644 index bb588363f..000000000 --- a/resources/units/aircraft/F-15ESE.yaml +++ /dev/null @@ -1,54 +0,0 @@ -description: - The F-15 has often been labeled as the greatest U.S. fighter aircraft from the - 1970s until the early 21st century. The F-15E is a multirole fighter and - exceeds in CAS operations. It served worldwide without suffering any confirmed - losses. -introduced: 1988 -manufacturer: McDonnell Douglas -origin: USA -price: 24 -role: Multirole Strike Fighter -max_range: 300 -use_f15e_waypoint_names: true -variants: - F-15E Strike Eagle (Suite 4+): {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-164 - channels: - type: common - # Radio 1 is the UHF AN/ARC-164, and Radio 2 is the V/UHF AN/ARC-210. We - # only ever allocate UHF for inter-flight, so we'd prefer to use radio 2 for - # intra-flight, but as is often the case the flight's frequency will be - # assigned to radio 1 channel 1 no matter what we do. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -tasks: - BAI: 760 - BARCAP: 240 - CAS: 760 - DEAD: 260 - Escort: 240 - Fighter sweep: 240 - Intercept: 240 - OCA/Aircraft: 760 - OCA/Runway: 630 - Strike: 640 - TARCAP: 240 -laser_codes: - - property: - id: Sta2LaserCode - digits: 3 - - property: - id: LCFTLaserCode - digits: 3 - - property: - id: Sta5LaserCode - digits: 3 - - property: - id: RCFTLaserCode - digits: 3 - - property: - id: Sta8LaserCode - digits: 3 -hit_points: 18 diff --git a/resources/units/aircraft/F-16A.yaml b/resources/units/aircraft/F-16A.yaml deleted file mode 100644 index b1af1051f..000000000 --- a/resources/units/aircraft/F-16A.yaml +++ /dev/null @@ -1,19 +0,0 @@ -description: The early verison of the F-16. It flew in Desert Storm. -price: 15 -max_range: 350 -variants: - F-16A: null -tasks: - Anti-ship: 100 - BAI: 570 - BARCAP: 420 - CAS: 570 - DEAD: 420 - Escort: 420 - Fighter sweep: 420 - Intercept: 420 - OCA/Aircraft: 570 - OCA/Runway: 570 - Strike: 570 - TARCAP: 420 -hit_points: 14 diff --git a/resources/units/aircraft/F-16C_50.yaml b/resources/units/aircraft/F-16C_50.yaml deleted file mode 100644 index a05161cdf..000000000 --- a/resources/units/aircraft/F-16C_50.yaml +++ /dev/null @@ -1,81 +0,0 @@ -description: "The F-16C is a single seat, single engine multirole fighter that - was developed in the 1970s. More than 4,500 units were manufactured and are - operated today by 26 countries where the aircraft performs numerous missions - that include air superiority, close air support, precision bombing, air - defense suppression, reconnaissance and more. Few other aircraft can match its - versatility, maneuverability, firepower, and huge production numbers. - - - Nicknamed the Viper by its pilots, the F-16 was designed with a reclined - seating position for high G tolerance and a single-piece bubble canopy for - exceptional visibility and comfort. Its lightweight and powerful F-110-GE-129 - engines provide a greater than 1:1 thrust ratio. - - - Housed in the nose of the Viper is a multifunction APG-68(V)5 radar. The - aircraft can also be equipped with multiple sensors such as the LITENING - targeting pod and HARM Targeting System (HTS). - - - The Viper is armed for air-to-air combat with Sidewinders, AMRAAMs, and an - internal 20mm 6-barrel Gatling gun. It can also be loaded with a wide range of - air-to-ground weapons that include general purpose bombs, rockets, canister - munition, Mavericks, laser- and GPS-guided bombs, and more" -introduced: 1991 -manufacturer: General Dynamics -origin: USA -price: 22 -role: Multirole Fighter -max_range: 350 -fuel: - # Parking 44 to RWY 06L at Anderson AFB. - taxi: 200 - # AB takeoff to 350/0.75, reduce to MIL and maintain 350/0.75 to 25k ft. - climb_ppm: 28.33 - # 0.85 mach for 100NM. - cruise_ppm: 12 - # MIL for 100NM. Occasional AB use. - combat_ppm: 26 - min_safe: 1000 -variants: - F-16CM Fighting Falcon (Block 50): {} - F-2A: {} -radios: - intra_flight: AN/ARC-222 - inter_flight: AN/ARC-164 - channels: - type: common - namer: viper - # COM2 is the AN/ARC-222, which is the VHF radio we want to use for - # intra-flight communication to leave COM1 open for UHF inter-flight. - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -# default_overrides: -# HelmetMountedDevice: 1 -# LAU3ROF: 0 -# LaserCode1: 8 -# LaserCode10: 8 -# LaserCode100: 6 -tasks: - BAI: 750 - BARCAP: 460 - CAS: 750 - DEAD: 450 - Escort: 460 - Fighter sweep: 460 - Intercept: 460 - OCA/Aircraft: 750 - OCA/Runway: 610 - SEAD: 170 - SEAD Escort: 170 - Strike: 610 - TARCAP: 460 -laser_codes: - - properties: - - id: LaserCode100 - digit: 2 - - id: LaserCode10 - digit: 1 - - id: LaserCode1 - digit: 0 -hit_points: 20 diff --git a/resources/units/aircraft/F-22A.yaml b/resources/units/aircraft/F-22A.yaml deleted file mode 100644 index e9549a9c5..000000000 --- a/resources/units/aircraft/F-22A.yaml +++ /dev/null @@ -1,25 +0,0 @@ -description: - The F-22A is an American single-seat, twin-engine, all-weather stealth - tactical fighter aircraft developed exclusively for the United States Air Force - (USAF). The result of the USAF's Advanced Tactical Fighter (ATF) program, the aircraft - was designed primarily as an air superiority fighter, but also has ground attack, - electronic warfare, and signal intelligence capabilities. Currently it is viewed - as the most advanced fighter in the world. -introduced: 2005 -manufacturer: Lockheed Martin -origin: USA -price: 40 -role: Stealth Air-Superiority Fighter -variants: - F-22A Raptor: {} -radios: - # I seriously doubt this is using the Mustang's radio but this is what was - # here before. - intra_flight: SCR-522 - inter_flight: SCR-522 -tasks: - BARCAP: 550 - Escort: 550 - Fighter sweep: 550 - Intercept: 550 - TARCAP: 550 diff --git a/resources/units/aircraft/F-4E.yaml b/resources/units/aircraft/F-4E.yaml deleted file mode 100644 index 861c585b9..000000000 --- a/resources/units/aircraft/F-4E.yaml +++ /dev/null @@ -1,36 +0,0 @@ -description: - Proving highly adaptable, the F-4 entered service with the Navy in 1961 - before it was adopted by the United States Marine Corps and the United States Air - Force, and by the mid-1960s it had become a major part of their air arms. Phantom - production ran from 1958 to 1981 with a total of 5,195 aircraft built, making it - the most produced American supersonic military aircraft in history, and cementing - its position as an iconic combat aircraft of the Cold War. The F-4 was used extensively - during the Vietnam War. It served as the principal air superiority fighter for the - U.S. Air Force, Navy, and Marine Corps and became important in the ground-attack - and aerial reconnaissance roles late in the war. -introduced: 1968 -manufacturer: McDonnell Douglas -origin: USA -price: 10 -role: Fighter-Bomber -max_range: 200 -variants: - F-4E Phantom II: {} - F-4EJ Kai Phantom II: {} - F-4F Phantom II: {} - Phantom F.3: {} -tasks: - BAI: 580 - BARCAP: 410 - CAS: 580 - DEAD: 400 - Escort: 410 - Fighter sweep: 410 - Intercept: 410 - OCA/Aircraft: 580 - OCA/Runway: 400 - SEAD: 120 - SEAD Escort: 120 - Strike: 400 - TARCAP: 410 -hit_points: 20 diff --git a/resources/units/aircraft/F-5E-3.yaml b/resources/units/aircraft/F-5E-3.yaml deleted file mode 100644 index 3fd70bead..000000000 --- a/resources/units/aircraft/F-5E-3.yaml +++ /dev/null @@ -1,51 +0,0 @@ -description: - "The F-5E was developed by Northrop Corporation in early 1970s. The light\ - \ tactical fighter is an upgraded version based on previous F-5A developments. The\ - \ F-5s' combat role encompasses air superiority, ground support, and ground attack.\ - \ Given its mission flexibility, ease of operation, and low cost, the Tiger II has,\ - \ and continues to serve, air forces across the globe.\n\nThe F-5\u0415 is armed\ - \ with two 20-mm \u041C39-\u04103 cannons with 280 rounds per each cannon. The cannons\ - \ are located in the nose section, forward of the cockpit. Special deflectors are\ - \ used to avoid compressor stall conditions caused by hot gas ingestion as a bi-product\ - \ of operating the M-39-A3. Each cannon is capable of firing at a rate of 1500 to\ - \ 1700 rounds per minute.\n\nEach wingtip incorporates a launcher rail capable of\ - \ firing AIM-9 infrared-guided missiles.\n\nFive hard points (one centerline pylon\ - \ and four underwing pylons) allow the aircraft to carry different types of air-to-ground\ - \ weapons (bombs, cluster munitions, and rockets) 6,400 pounds (about 3000 kg) in\ - \ total. In addition, illumination ammunition and cargo containers can be attached.\ - \ To increase flight duration and range, external fuel tanks can be attached to\ - \ three hard points (a centerline pylon and two inboard pylons). Maneuverability\ - \ and speed can be maximized in combat by jettisoning all external stores." -introduced: 1975 -manufacturer: Northrop -origin: USA -price: 12 -role: Light Fighter -max_range: 100 -gunfighter: true -variants: - F-5E Tiger II: {} -# default_overrides: -# ChaffBurst: 0 -# ChaffBurstInt: 0 -# ChaffSalvo: 0 -# ChaffSalvoInt: 0 -# FlareBurst: 0 -# FlareBurstInt: 0 -# LAU3ROF: 0 -# LAU68ROF: 0 -# LaserCode1: 8 -# LaserCode10: 8 -# LaserCode100: 6 -tasks: - BAI: 260 - BARCAP: 200 - CAS: 260 - Escort: 200 - Fighter sweep: 200 - Intercept: 200 - OCA/Aircraft: 260 - OCA/Runway: 190 - Strike: 200 - TARCAP: 200 -hit_points: 16 diff --git a/resources/units/aircraft/F-86F Sabre.yaml b/resources/units/aircraft/F-86F Sabre.yaml deleted file mode 100644 index 9df63b472..000000000 --- a/resources/units/aircraft/F-86F Sabre.yaml +++ /dev/null @@ -1,29 +0,0 @@ -always_keeps_gun: true -description: - "The North American F-86F Sabre was the most capable western fighter\ - \ of the early- to mid-1950s. This swept wing, single engine jet was the most important\ - \ western aircraft of the Korean War and often tangled with Russian-made MiG-15s\ - \ over the infamous \u201CMiG Alley\u201D. It was a hard struggle not only for the\ - \ Korean sky, but also between two excellent aircraft builders of the East and West.\ - \ In addition to its primary role as an air-to-air fighter, the Sabre could also\ - \ carry bombs and air-to-ground rockets to attack ground targets." -introduced: 1953 -manufacturer: North American -origin: USA -price: 8 -role: Fighter -gunfighter: true -variants: - F-86F Sabre: {} -tasks: - BAI: 250 - BARCAP: 150 - CAS: 250 - Escort: 150 - Fighter sweep: 150 - Intercept: 150 - OCA/Aircraft: 250 - OCA/Runway: 180 - Strike: 190 - TARCAP: 150 -hit_points: 15 diff --git a/resources/units/aircraft/FA-18C_hornet.yaml b/resources/units/aircraft/FA-18C_hornet.yaml deleted file mode 100644 index 3d505bb88..000000000 --- a/resources/units/aircraft/FA-18C_hornet.yaml +++ /dev/null @@ -1,71 +0,0 @@ -carrier_capable: true -description: - 'The F/A-18C Hornet is twin engine, supersonic fighter that is flown - by a single pilot in a "glass cockpit". It combines extreme maneuverability , a - deadly arsenal of weapons, and the ability to operate from an aircraft carrier. - Operated by several nations, this multi-role fighter has been instrumental in conflicts - from 1986 to today. - - - The Hornet is equipped with a large suite of sensors that includes a radar, targeting - pod, and a helmet mounted sight. In addition to its internal 20mm cannon, the Hornet - can be armed with a large assortment of unguided bombs and rockets, laser and GPS-guided - bombs, air-to-surface missiles of all sorts, and both radar and infrared-guided - air-to-air missiles. - - - The Hornet is also known for its extreme, slow-speed maneuverability in a dogfight. - Although incredibly deadly, the Hornet is also a very easy aircraft to fly.' -introduced: 1987 -manufacturer: McDonnell Douglas -origin: USA -price: 24 -role: Carrier-based Multirole Fighter -# DCS default livery for the Hornet is the Blue Angels. -default_livery: "VFA-34" -fuel: - # Parking A1 to RWY 32 at Akrotiri. - taxi: 170 - # AB takeoff to 350/0.85, reduce to MIL and maintain 350 to 25k ft. - climb_ppm: 44.25 - # 0.85 mach for 100NM. - cruise_ppm: 22.1 - # ~0.9 mach for 100NM. Occasional AB use. - combat_ppm: 27.5 - min_safe: 2000 -variants: - CF-188 Hornet: {} - EF-18A+ Hornet: {} - F/A-18C Hornet (Lot 20): {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - # DCS will clobber channel 1 of the first radio compatible with the flight's - # assigned frequency. Since the F/A-18's two radios are both AN/ARC-210s, - # radio 1 will be compatible regardless of which frequency is assigned, so - # we must use radio 1 for the intra-flight radio. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -utc_kneeboard: true -# default_overrides: -# HelmetMountedDevice: 1 -# InnerBoard: 0 -# OuterBoard: 0 -tasks: - Anti-ship: 150 - BAI: 740 - BARCAP: 450 - CAS: 740 - DEAD: 440 - Escort: 450 - Fighter sweep: 450 - Intercept: 450 - OCA/Aircraft: 740 - OCA/Runway: 600 - SEAD: 160 - SEAD Escort: 160 - Strike: 600 - TARCAP: 450 -hit_points: 20 diff --git a/resources/units/aircraft/FA-18E.yaml b/resources/units/aircraft/FA-18E.yaml deleted file mode 100644 index dc86cb4c3..000000000 --- a/resources/units/aircraft/FA-18E.yaml +++ /dev/null @@ -1,78 +0,0 @@ -carrier_capable: true -description: - "The F/A-18E Super Hornet is a single-seat, twin engine, carrier-capable, multirole - fighter aircraft. The Super Hornets are larger and more advanced derivatives of the - McDonnell Douglas F/A-18C and D Hornets, also known as legacy Hornets. - - - The Super Hornet is equipped with a large suite of sensors that includes a radar, targeting - pod, and a helmet mounted sight. In addition to its internal 20mm cannon, the Super Hornet - can be armed with a large assortment of unguided bombs and rockets, laser and GPS-guided - bombs, air-to-surface missiles of all sorts, and both radar and infrared-guided - air-to-air missiles. - - - The Super Hornet is also known for its extreme, slow-speed maneuverability in a dogfight. - Although incredibly deadly, the Super Hornet is also a very easy aircraft to fly." -introduced: 1999 -manufacturer: McDonnell Douglas -origin: USA -price: 25 -role: Carrier-based Multirole Fighter -fuel: - # Parking A1 to RWY 32 at Akrotiri. - taxi: 170 - # AB takeoff to 350/0.85, reduce to MIL and maintain 350 to 25k ft. - climb_ppm: 44.25 - # 0.85 mach for 100NM. - cruise_ppm: 22.1 - # ~0.9 mach for 100NM. Occasional AB use. - combat_ppm: 27.5 - min_safe: 2000 -variants: - F/A-18E Super Hornet: {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - # DCS will clobber channel 1 of the first radio compatible with the flight's - # assigned frequency. Since the F/A-18's two radios are both AN/ARC-210s, - # radio 1 will be compatible regardless of which frequency is assigned, so - # we must use radio 1 for the intra-flight radio. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -utc_kneeboard: true -# default_overrides: -# HelmetMountedDevice: 1 -# InnerBoard: 0 -# OuterBoard: 0 -tasks: - Anti-ship: 150 - BAI: 740 - BARCAP: 450 - CAS: 740 - DEAD: 440 - Escort: 450 - Fighter sweep: 450 - Intercept: 450 - OCA/Aircraft: 740 - OCA/Runway: 600 - SEAD: 430 - SEAD Escort: 430 - Strike: 600 - TARCAP: 450 -hit_points: 20 -weapon_injections: # AGM-154B only works for AI - 2: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 3: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 7: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 8: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" diff --git a/resources/units/aircraft/FA-18F.yaml b/resources/units/aircraft/FA-18F.yaml deleted file mode 100644 index a14b6c76d..000000000 --- a/resources/units/aircraft/FA-18F.yaml +++ /dev/null @@ -1,78 +0,0 @@ -carrier_capable: true -description: - "The F/A-18F Super Hornet is a tandem-seat, twin engine, carrier-capable, multirole - fighter aircraft. The Super Hornets are larger and more advanced derivatives of the - McDonnell Douglas F/A-18C and D Hornets, also known as legacy Hornets. - - - The Super Hornet is equipped with a large suite of sensors that includes a radar, targeting - pod, and a helmet mounted sight. In addition to its internal 20mm cannon, the Super Hornet - can be armed with a large assortment of unguided bombs and rockets, laser and GPS-guided - bombs, air-to-surface missiles of all sorts, and both radar and infrared-guided - air-to-air missiles. - - - The Super Hornet is also known for its extreme, slow-speed maneuverability in a dogfight. - Although incredibly deadly, the Super Hornet is also a very easy aircraft to fly." -introduced: 2006 -manufacturer: Boeing -origin: USA -price: 25 -role: Carrier-based Multirole Fighter -fuel: - # Parking A1 to RWY 32 at Akrotiri. - taxi: 170 - # AB takeoff to 350/0.85, reduce to MIL and maintain 350 to 25k ft. - climb_ppm: 44.25 - # 0.85 mach for 100NM. - cruise_ppm: 22.1 - # ~0.9 mach for 100NM. Occasional AB use. - combat_ppm: 27.5 - min_safe: 2000 -variants: - F/A-18F Super Hornet: {} -radios: - intra_flight: AN/ARC-210 - inter_flight: AN/ARC-210 - channels: - type: common - # DCS will clobber channel 1 of the first radio compatible with the flight's - # assigned frequency. Since the F/A-18's two radios are both AN/ARC-210s, - # radio 1 will be compatible regardless of which frequency is assigned, so - # we must use radio 1 for the intra-flight radio. - intra_flight_radio_index: 1 - inter_flight_radio_index: 2 -utc_kneeboard: true -# default_overrides: -# HelmetMountedDevice: 1 -# InnerBoard: 0 -# OuterBoard: 0 -tasks: - Anti-ship: 150 - BAI: 740 - BARCAP: 450 - CAS: 740 - DEAD: 440 - Escort: 450 - Fighter sweep: 450 - Intercept: 450 - OCA/Aircraft: 740 - OCA/Runway: 600 - SEAD: 430 - SEAD Escort: 430 - Strike: 600 - TARCAP: 450 -hit_points: 20 -weapon_injections: # AGM-154B only works for AI - 2: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 3: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 7: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" - 8: - - "{AGM-154B}" - - "{BRU57_2*AGM-154B}" diff --git a/resources/units/aircraft/FW-190A8.yaml b/resources/units/aircraft/FW-190A8.yaml deleted file mode 100644 index b7fe3f20c..000000000 --- a/resources/units/aircraft/FW-190A8.yaml +++ /dev/null @@ -1,47 +0,0 @@ -always_keeps_gun: true -description: - "Designed for the German Luftwaffe by famed aircraft designer Kurt Tank - in the late-1930s, the Fw 190 was the backbone of the Luftwaffe in both fighter - and attack bomber roles. Powered by a large radial engine, the A version of the - Focke-Wulf 190 was superior in many ways to the Bf 109s and Spitfires at the time - of its introduction. In fact, this led to the development of the Mk.IX version of - the Spitfire. - - - Many of the Luftwaffe's aces racked up their impressive kill counts in the Fw 190 - A due to its impressive fire power, excellent low to medium altitude performance, - durability, and ease of flying. It saw action on both the eastern and western fronts - where it was both respected and feared by allied pilots. Armament included two fuselage-mounted - 13-mm MG 131 machine guns and four wing-mounted MG 151/20E 20mm cannons. The Anton - could also be loaded with unguided rockets and bombs. - - - The A-8 version of the Fw 190 entered production in February 1944, and it was powered - by a BMW 801 D-2 radial engine. In addition to excellent low- and medium-altitude - performance, the engine was also very rugged. Along with the F-8 version, it also - had thicker armor around the engine. The engine also received the C3 injection system - that provided an emergency boost of 1,980 PS in short durations." -introduced: 1944 -manufacturer: Focke-Wulf -origin: Germany -price: 3 -role: Fighter -gunfighter: true -variants: - Fw 190 A-8 Anton: {} -kneeboard_units: "metric" -# default_overrides: -# FW_MW50TankContents: 0 -tasks: - BAI: 30 - BARCAP: 40 - CAS: 30 - DEAD: 0 - Escort: 40 - Fighter sweep: 40 - Intercept: 40 - OCA/Aircraft: 30 - OCA/Runway: 0 - Strike: 0 - TARCAP: 40 -hit_points: 18 diff --git a/resources/units/aircraft/FW-190D9.yaml b/resources/units/aircraft/FW-190D9.yaml deleted file mode 100644 index 1661d9fa3..000000000 --- a/resources/units/aircraft/FW-190D9.yaml +++ /dev/null @@ -1,36 +0,0 @@ -always_keeps_gun: true -description: - "The Focke-Wulf Fw 190 is widely regarded as Germany's best fighter aircraft\ - \ of World War II. Its appearance in the skies over France in August 1941 was a\ - \ rude shock to the Allies, as it was clearly superior to any other plane. For nearly\ - \ a year, the Fw 190 was the unmatched champion of the air war in Europe. The Fw\ - \ 190 had speed and high altitude performance as its two great assets.\n\nThe development\ - \ of advanced allied fighters resulted in the Fw 190 D\u20139 variant which first\ - \ saw service in September 1944. This variant had a larger nose that housed a more\ - \ powerful Junkers Jumo engine that produced 2,100 hp with the MW-50 boost system.\ - \ The D-9 was designed for high altitude aerial combat and is a worthy adversary\ - \ to the P-51D Mustang." -introduced: 1944 -manufacturer: Focke-Wulf -origin: Germany -price: 5 -role: Fighter -gunfighter: true -variants: - Fw 190 D-9 Dora: {} -kneeboard_units: "metric" -# default_overrides: -# FW_MW50TankContents: 1 -tasks: - BAI: 40 - BARCAP: 50 - CAS: 40 - DEAD: 10 - Escort: 50 - Fighter sweep: 50 - Intercept: 50 - OCA/Aircraft: 40 - OCA/Runway: 10 - Strike: 10 - TARCAP: 50 -hit_points: 18 diff --git a/resources/units/aircraft/H-6J.yaml b/resources/units/aircraft/H-6J.yaml deleted file mode 100644 index 74d1e4391..000000000 --- a/resources/units/aircraft/H-6J.yaml +++ /dev/null @@ -1,27 +0,0 @@ -description: - "The Xian H-6J naval bomber is a licence-built version of the Soviet Tupolev Tu-16 twin-engine jet bomber, - built for China's People's Liberation Army Air Force (PLAAF). - It has the capability to carry KD-20 and KD-63 cruise missiles." -introduced: 1969 -manufacturer: Xian -origin: China -price: 40 -role: Maritime Strike Bomber -max_range: 2000 -variants: - H-6J Badger: {} - Tu-16 Badger: - introduced: 1954 - manufacturer: Tupolev - origin: USSR/Russia -# default_overrides: -# Belly_Bay_Door: false -tasks: - Anti-ship: 160 - BAI: 380 - CAS: 380 - DEAD: 180 - OCA/Aircraft: 380 - OCA/Runway: 640 - Strike: 650 -hit_points: 18 diff --git a/resources/units/aircraft/Hercules.yaml b/resources/units/aircraft/Hercules.yaml deleted file mode 100644 index d5aaf80b0..000000000 --- a/resources/units/aircraft/Hercules.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: - The Lockheed Martin C-130J Super Hercules is a four-engine turboprop - military transport aircraft. The C-130J is a comprehensive update of the Lockheed - C-130 Hercules, with new engines, flight deck, and other systems. As of February - 2018, 400 C-130J aircraft have been delivered to 17 nations. -introduced: 1999 -manufacturer: Lockheed -origin: USA -price: 18 -role: Transport -max_range: 1000 -cabin_size: 24 # It should have more but we do not want so much for CTLD to be possible -variants: - C-130J-30 Super Hercules: {} -tasks: - Air Assault: 0 - BAI: 810 - CAS: 810 - OCA/Aircraft: 810 - Transport: 140 diff --git a/resources/units/aircraft/I-16.yaml b/resources/units/aircraft/I-16.yaml deleted file mode 100644 index 73c30d36f..000000000 --- a/resources/units/aircraft/I-16.yaml +++ /dev/null @@ -1,31 +0,0 @@ -description: - "I-16 - Soviet single-engine monoplane fighter of 1930s created by aircraft\ - \ designer Nikolai Polikarpov\u2019s design bureau. It was the one of the world\u2019\ - s first fighters with landing gear retraction system. It was I-16 which stood the\ - \ air fighting against famous Messerschmitt Bf 109.\n\nOver a period of its history\ - \ I-16 was upgraded a lot. New modifications of aircraft were created and adopted\ - \ almost every year. I-16 type 24 was further development of I-16 type 18.\n\nIt\ - \ is one of the most famous fighters taking part in World War II. It was different\ - \ from all its \u201Ccontemporaries\u201D in configuration and flight characteristics.\ - \ Its uniqueness and distinction were defined by minimum size, dome-shaped fuselage,\ - \ small wing, dorsal spine." -introduced: 1935 -manufacturer: Polikarpov -origin: USSR/Russia -price: 2 -role: Fighter -gunfighter: true -variants: - I-16 Ishak: {} -# default_overrides: -# landingTorch: false -tasks: - BAI: 60 - BARCAP: 0 - CAS: 60 - Escort: 0 - Fighter sweep: 0 - Intercept: 0 - OCA/Aircraft: 60 - TARCAP: 0 -hit_points: 15 diff --git a/resources/units/aircraft/IL-76MD.yaml b/resources/units/aircraft/IL-76MD.yaml deleted file mode 100644 index b03b361b8..000000000 --- a/resources/units/aircraft/IL-76MD.yaml +++ /dev/null @@ -1,7 +0,0 @@ -price: 20 -max_range: 1000 -variants: - IL-76MD: null -tasks: - Transport: 120 -hit_points: 60 diff --git a/resources/units/aircraft/IL-78M.yaml b/resources/units/aircraft/IL-78M.yaml deleted file mode 100644 index b0fe01227..000000000 --- a/resources/units/aircraft/IL-78M.yaml +++ /dev/null @@ -1,12 +0,0 @@ -price: 20 -max_group_size: 1 -max_range: 1000 -patrol: - # ~280 knots IAS. - speed: 400 - altitude: 21000 -variants: - IL-78M: null -tasks: - Refueling: 30 -hit_points: 60 diff --git a/resources/units/aircraft/J-11A.yaml b/resources/units/aircraft/J-11A.yaml deleted file mode 100644 index 4f5e0247a..000000000 --- a/resources/units/aircraft/J-11A.yaml +++ /dev/null @@ -1,21 +0,0 @@ -description: - The Shenyang J-11 (NATO reporting name Flanker-L) is a twin-engine jet - fighter whose airframe is based on the Soviet-designed Sukhoi Su-27. It is manufactured - by the Shenyang Aircraft Corporation (SAC). The aircraft is operated by the People's - Liberation Army Air Force (PLAAF) and the People's Liberation Army Naval Air Force - (PLANAF). -introduced: 1998 -manufacturer: Shenyang -origin: China -price: 22 -role: Air-Superiority Fighter -variants: - J-11A Flanker-L: {} -kneeboard_units: "metric" -tasks: - BARCAP: 500 - Escort: 500 - Fighter sweep: 500 - Intercept: 500 - TARCAP: 500 -hit_points: 18 diff --git a/resources/units/aircraft/JAS39Gripen.yaml b/resources/units/aircraft/JAS39Gripen.yaml deleted file mode 100644 index 4cc1dc8ba..000000000 --- a/resources/units/aircraft/JAS39Gripen.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: - The Saab JAS 39 Gripen is a light single-engine multirole fighter aircraft - manufactured by the Swedish aerospace company Saab AB. The Gripen has a delta wing - and canard configuration with relaxed stability design and fly-by-wire flight controls. - Various versions have been built, grouped as A-, C- and E-series. This is the AA - Version, since the Mod for this aircraft splitted it in an AA and AG Version. -introduced: 2002 -manufacturer: Saab AB -origin: Sweden -price: 21 -role: Fighter -variants: - JAS 39 Gripen: {} -radios: - intra_flight: R&S Series 6000 - inter_flight: R&S Series 6000 -tasks: - BARCAP: 430 - Escort: 430 - Fighter sweep: 430 - Intercept: 430 - TARCAP: 430 diff --git a/resources/units/aircraft/JAS39Gripen_AG.yaml b/resources/units/aircraft/JAS39Gripen_AG.yaml deleted file mode 100644 index a76026db6..000000000 --- a/resources/units/aircraft/JAS39Gripen_AG.yaml +++ /dev/null @@ -1,26 +0,0 @@ -description: - The Saab JAS 39 Gripen is a light single-engine multirole fighter aircraft - manufactured by the Swedish aerospace company Saab AB. The Gripen has a delta wing - and canard configuration with relaxed stability design and fly-by-wire flight controls. - Various versions have been built, grouped as A-, C- and E-series. This is the AG - Version, since the Mod for this aircraft splitted it in an AA and AG Version. -introduced: 2002 -manufacturer: Saab AB -origin: Sweden -price: 20 -role: Attack -variants: - JAS 39 Gripen A/G: {} -radios: - intra_flight: R&S Series 6000 - inter_flight: R&S Series 6000 -tasks: - Anti-ship: 140 - BAI: 710 - CAS: 710 - DEAD: 230 - OCA/Aircraft: 710 - OCA/Runway: 540 - SEAD: 80 - SEAD Escort: 80 - Strike: 540 diff --git a/resources/units/aircraft/JF-17.yaml b/resources/units/aircraft/JF-17.yaml deleted file mode 100644 index 919b957ed..000000000 --- a/resources/units/aircraft/JF-17.yaml +++ /dev/null @@ -1,56 +0,0 @@ -description: - "JF-17 is a single seat, single engine, multirole light fighter that\ - \ was joint developed by AVIC Chengdu and Pakistan Aeronautical Complex (PAC). The\ - \ design phase of JF-17 \"Thunder\" finished at May 31st, 2002, and the maiden flight\ - \ was made on August 25th, 2003. The first plane delivered to PAF (Pakistan Air\ - \ Force) in 2007. Currently several different blocks of JF-17s are in service in\ - \ Pakistan and Myanmar air forces. There are also several countries interested in\ - \ purchasing this fighter jet. On February 27th, 2019, \"Thunder\" has withstood\ - \ the test of actual combat and helped PAF win an appreciable victory.\n\n\"Thunder\"\ - \ is a type of fighter that specifically tailored for PAF. The development plan\ - \ of her predecessor can even be traced back to 1985. At first, PAF was only looking\ - \ for a fighter that can replace Shenyang J-6 (Chinese version of Mig-19), but they\ - \ were not satisfied with Chengdu\u2019s J-7M. After more than 20 years of development,\ - \ the final product \"Thunder\" becomes completely different from J-7M.\n\n\"Thunder\"\ - \ has a bubble canopy of great view, pretty strake-wing layout and advanced avionics.\ - \ KLJ-7 radar provides excellent air to ground capability. WMD-7 targeting pod can\ - \ help \"Thunder\" searching for targets in combat." -introduced: 2007 -manufacturer: PAC/CAC -origin: Pakistan/China -price: 24 -role: Multirole Fighter -variants: - FC-1 Fierce Dragon: - introduced: null - JF-17 Thunder: {} -radios: - intra_flight: R&S M3AR VHF - inter_flight: R&S M3AR UHF - channels: - type: common - # Same naming pattern as the Viper, so just reuse that. - namer: viper - intra_flight_radio_index: 1 - inter_flight_radio_index: 1 -# default_overrides: -# AARProbe: false -# LaserCode1: 8 -# LaserCode10: 8 -# LaserCode100: 6 -tasks: - Anti-ship: 110 - BAI: 700 - BARCAP: 440 - CAS: 700 - DEAD: 460 - Escort: 440 - Fighter sweep: 440 - Intercept: 440 - OCA/Aircraft: 700 - OCA/Runway: 580 - SEAD: 180 - SEAD Escort: 180 - Strike: 580 - TARCAP: 440 -hit_points: 18 diff --git a/resources/units/aircraft/Ju-88A4.yaml b/resources/units/aircraft/Ju-88A4.yaml deleted file mode 100644 index 8192cd9f5..000000000 --- a/resources/units/aircraft/Ju-88A4.yaml +++ /dev/null @@ -1,30 +0,0 @@ -always_keeps_gun: true -description: - The Junkers Ju 88 is a German World War II Luftwaffe twin-engined multirole - combat aircraft. Junkers Aircraft and Motor Works (JFM) designed the plane in the - mid-1930s as a so-called Schnellbomber ('fast bomber') that would be too fast for - fighters of its era to intercept. It suffered from technical problems during its - development and early operational periods but became one of the most versatile combat - aircraft of the war. Like a number of other Luftwaffe bombers, it served as a bomber, - dive bomber, night fighter, torpedo bomber, reconnaissance aircraft, heavy fighter - and at the end of the war, as a flying bomb. Despite a protracted development, it - became one of the Luftwaffe's most important aircraft. The assembly line ran constantly - from 1936 to 1945 and more than 15,000 Ju 88s were built in dozens of variants, - more than any other twin-engine German aircraft of the period. Throughout production - the basic structure of the aircraft remained unchanged. -introduced: 1940 -manufacturer: Junkers -origin: Germany -price: 14 -role: Tactical/Torpedo Bomber -variants: - Ju 88 A-4: {} -tasks: - Anti-ship: 30 - BAI: 150 - CAS: 150 - DEAD: 160 - OCA/Aircraft: 150 - OCA/Runway: 130 - Strike: 130 -hit_points: 18 diff --git a/resources/units/aircraft/KC-135.yaml b/resources/units/aircraft/KC-135.yaml deleted file mode 100644 index 7035c23c6..000000000 --- a/resources/units/aircraft/KC-135.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: - The Boeing KC-135 Stratotanker is a military aerial refueling aircraft that - was developed from the Boeing 367-80 prototype, alongside the Boeing 707 - airliner. -introduced: 1957 -max_group_size: 1 -manufacturer: Beoing -origin: USA -price: 25 -role: Tanker -max_range: 1000 -patrol: - # ~300 knots IAS. - speed: 445 - altitude: 24000 -variants: - KC-135 Stratotanker: {} -tasks: - Refueling: 50 -hit_points: 60 diff --git a/resources/units/aircraft/KC130.yaml b/resources/units/aircraft/KC130.yaml deleted file mode 100644 index 804281bb8..000000000 --- a/resources/units/aircraft/KC130.yaml +++ /dev/null @@ -1,18 +0,0 @@ -description: - The Lockheed Martin (previously Lockheed) KC-130 is a family of the extended-range - tanker version of the C-130 Hercules transport aircraft modified for aerial refueling. -introduced: 1962 -manufacturer: Lockheed Martin -origin: USA -price: 25 -role: Tanker -max_range: 1000 -patrol: - # ~210 knots IAS, roughly the max for the KC-130 at altitude. - speed: 370 - altitude: 22000 -variants: - KC-130: {} -tasks: - Refueling: 10 -hit_points: 18 diff --git a/resources/units/aircraft/KC130J.yaml b/resources/units/aircraft/KC130J.yaml deleted file mode 100644 index 697dee25b..000000000 --- a/resources/units/aircraft/KC130J.yaml +++ /dev/null @@ -1,19 +0,0 @@ -description: - The Lockheed Martin (previously Lockheed) KC-130 is a family of the extended-range - tanker version of the C-130 Hercules transport aircraft modified for aerial refueling. - This version of the KC-130 tanker is designed for refueling at speeds of 120-130kts, - enabling refueling of helicopters such as the UH-60L. -introduced: 2004 -manufacturer: Lockheed Martin -origin: USA -price: 25 -role: Tanker -max_range: 1000 -patrol: - # ~125 knots IAS - speed: 180 - altitude: 22000 -variants: - KC-130J: {} -tasks: - Refueling: 20 diff --git a/resources/units/aircraft/KC135MPRS.yaml b/resources/units/aircraft/KC135MPRS.yaml deleted file mode 100644 index 319fb0150..000000000 --- a/resources/units/aircraft/KC135MPRS.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: - The Boeing KC-135 Stratotanker is a military aerial refueling aircraft - that was developed from the Boeing 367-80 prototype, alongside the Boeing 707 airliner. This - model has the Multi-point Refueling System modification, allowing for probe and - drogue refuelling. -introduced: 1994 -manufacturer: Boeing -origin: USA -price: 25 -role: Tanker -max_range: 1000 -patrol: - # 300 knots IAS. - speed: 440 - altitude: 23000 -variants: - KC-135 Stratotanker MPRS: {} -tasks: - Refueling: 40 -hit_points: 18 diff --git a/resources/units/aircraft/KJ-2000.yaml b/resources/units/aircraft/KJ-2000.yaml deleted file mode 100644 index cea50dd89..000000000 --- a/resources/units/aircraft/KJ-2000.yaml +++ /dev/null @@ -1,9 +0,0 @@ -price: 50 -max_range: 2000 -patrol: - altitude: 40000 -variants: - KJ-2000: null -tasks: - AEW&C: 0 -hit_points: 18 diff --git a/resources/units/aircraft/Ka-50.yaml b/resources/units/aircraft/Ka-50.yaml deleted file mode 100644 index 25fd993a1..000000000 --- a/resources/units/aircraft/Ka-50.yaml +++ /dev/null @@ -1,32 +0,0 @@ -class: Helicopter -always_keeps_gun: true -carrier_capable: true -description: - "The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly - single-seat, Russian attack helicopter that has seen combat in the Northern Caucasus. - It combines a high performance dual rotor system with a deadly weapons payload of - guided missiles, rockets, bombs, and a 30mm cannon. The Ka-50 is also unique in - that it has an ejection seat." -introduced: 1995 -lha_capable: true -cabin_size: 0 # Can not transport troops -can_carry_crates: true -manufacturer: Kamov -origin: USSR/Russia -price: 20 -role: Attack -variants: - Ka-50 Hokum: {} -radios: - intra_flight: R-800L1 - inter_flight: R-800L1 - # The R-800L1 doesn't have preset channels, and the other radio is for - # communications with FAC and ground units, which don't currently have - # radios assigned, so no channels to configure. -kneeboard_units: "metric" -tasks: - BAI: 430 - CAS: 430 - DEAD: 113 - OCA/Aircraft: 430 -hit_points: 15 diff --git a/resources/units/aircraft/Ka-50_3.yaml b/resources/units/aircraft/Ka-50_3.yaml deleted file mode 100644 index 433ea6c30..000000000 --- a/resources/units/aircraft/Ka-50_3.yaml +++ /dev/null @@ -1,32 +0,0 @@ -class: Helicopter -always_keeps_gun: true -carrier_capable: true -description: - "The Ka-50 Black Shark (NATO reporting name: Hokum) is a unique and deadly - single-seat, Russian attack helicopter that has seen combat in the Northern - Caucasus. It combines a high performance dual rotor system with a deadly - weapons payload of guided missiles, rockets, bombs, and a 30mm cannon. The - Ka-50 is also unique in that it has an ejection seat." -introduced: 1995 -lha_capable: true -cabin_size: 0 # Can not transport troops -can_carry_crates: true -manufacturer: Kamov -origin: USSR/Russia -price: 20 -role: Attack -variants: - Ka-50 Hokum (Blackshark 3): {} -radios: - intra_flight: R-800L1 - inter_flight: R-800L1 - # The R-800L1 doesn't have preset channels, and the other radio is for - # communications with FAC and ground units, which don't currently have - # radios assigned, so no channels to configure. -kneeboard_units: "metric" -tasks: - BAI: 440 - CAS: 440 - DEAD: 114 - OCA/Aircraft: 440 -hit_points: 15 diff --git a/resources/units/aircraft/L-39ZA.yaml b/resources/units/aircraft/L-39ZA.yaml deleted file mode 100644 index 3dd40be0b..000000000 --- a/resources/units/aircraft/L-39ZA.yaml +++ /dev/null @@ -1,33 +0,0 @@ -description: - "Two seat Jet trainer aircraft L-39C is intended for basic and advanced\ - \ pilot training in visual and instrument flight rules weather conditions, day and\ - \ night and also for combat use against air and ground targets. Its development\ - \ started in the middle 60s of the last century by the Czech \u201CAero Vodochody\u201D\ - . In the 70s the aircraft has entered service and is still in the operational use\ - \ in over 30 countries worldwide." -introduced: 1977 -manufacturer: Aero -origin: Czechoslovakia -price: 10 -role: Light Attack -gunfighter: true -variants: - L-39ZA Albatros: {} -kneeboard_units: "metric" -# default_overrides: -# DismountIFRHood: false -# NS430allow: true -# NetCrewControlPriority: 1 -# SoloFlight: false -tasks: - BAI: 220 - BARCAP: 120 - CAS: 220 - Escort: 120 - Fighter sweep: 120 - Intercept: 120 - OCA/Aircraft: 220 - OCA/Runway: 160 - Strike: 160 - TARCAP: 120 -hit_points: 15 diff --git a/resources/units/aircraft/M-2000C.yaml b/resources/units/aircraft/M-2000C.yaml deleted file mode 100644 index 11e03d007..000000000 --- a/resources/units/aircraft/M-2000C.yaml +++ /dev/null @@ -1,51 +0,0 @@ -description: - The M-2000C is a multi-role, French-designed, 4th generation fighter. - It was designed in the 1970s as a lightweight fighter and in excess of 600 M-2000C - aircraft have been built. The M2000C is a single-engine fighter will a low-set delta - wing with no horizontal tail. It has excellent maneuverability given its relaxed - stability and fly-by-wire flight control system. The M2000C also includes a multi-mode - RDI radar that is capable tracking and engaging targets at beyond visual ranges. - In addition to engaging other aircraft with cannon and missiles, the M2000C can - also engage ground targets with cannon, rockets and bombs. -introduced: 1983 -manufacturer: Dassault -origin: France -price: 17 -role: Multirole Fighter -max_range: 400 -variants: - Mirage 2000C: {} -radios: - intra_flight: TRT ERA 7200 UHF - inter_flight: TRT ERA 7000 V/UHF - channels: - type: common - namer: mirage - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -# default_overrides: -# DisableVTBExport: false -# EnableTAF: true -# ForceINSRules: false -# GunBurst: 1 -# InitHotDrift: 0 -# LaserCode1: 8 -# LaserCode10: 8 -# LaserCode100: 6 -# LoadNVGCase: false -# NoDDMSensor: true -# ReadyALCM: true -# RocketBurst: 6 -# WpBullseye: 0 -tasks: - BAI: 350 - BARCAP: 230 - CAS: 350 - Escort: 230 - Fighter sweep: 230 - Intercept: 230 - OCA/Aircraft: 350 - OCA/Runway: 320 - Strike: 320 - TARCAP: 230 -hit_points: 18 diff --git a/resources/units/aircraft/MB-339A.yaml b/resources/units/aircraft/MB-339A.yaml deleted file mode 100644 index 60d6313e8..000000000 --- a/resources/units/aircraft/MB-339A.yaml +++ /dev/null @@ -1,29 +0,0 @@ -introduced: 1979 -manufacturer: Aermacchi -origin: Italy -price: 10 -role: Light Attack -max_range: 200 -variants: - MB-339A: {} -radios: - intra_flight: SRT-651/N - inter_flight: AN/ARC-150(V) 2 - channels: - # The common allocator is sufficient for Liberation's purposes. There are - # more than 20 channels available on COMM2 (manual says 100, ME says 30, - # presumably only 30 can be truly *pre* set, and the other 70 can be set in - # the cockpit). We never need that many though, so no sense customizing - # further. - type: common - # COMM1 us UHF only. COMM2 is V/UHF. We prefer allocating intra-flight on - # VHF because it's less contested, so intra-flight goes to COMM2. - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -tasks: - BAI: 240 - CAS: 240 - OCA/Aircraft: 240 - OCA/Runway: 200 - Strike: 180 -hit_points: 18 diff --git a/resources/units/aircraft/MQ-9 Reaper.yaml b/resources/units/aircraft/MQ-9 Reaper.yaml deleted file mode 100644 index 7b3da29a9..000000000 --- a/resources/units/aircraft/MQ-9 Reaper.yaml +++ /dev/null @@ -1,8 +0,0 @@ -price: 10 -variants: - MQ-9 Reaper: null -tasks: - BAI: 10 - CAS: 10 - OCA/Aircraft: 10 -hit_points: 18 diff --git a/resources/units/aircraft/Mi-24P.yaml b/resources/units/aircraft/Mi-24P.yaml deleted file mode 100644 index b66855051..000000000 --- a/resources/units/aircraft/Mi-24P.yaml +++ /dev/null @@ -1,34 +0,0 @@ -class: Helicopter -always_keeps_gun: true -description: - "The Mil Mi-24 (Russian: \u041C\u0438\u043B\u044C \u041C\u0438-24; NATO\ - \ reporting name: Hind) is a large helicopter gunship, attack helicopter and low-capacity\ - \ troop transport with room for eight passengers. It is produced by Mil Moscow Helicopter\ - \ Plant and has been operated since 1972 by the Soviet Air Force and its successors,\ - \ along with 48 other nations. Soviet pilots called the Mi-24 the 'flying tank'\ - \ (Russian: \u043B\u0435\u0442\u0430\u044E\u0449\u0438\u0439 \u0442\u0430\u043D\u043A\ - , romanized: letayushchiy tank), a term used historically with the famous World\ - \ War II Soviet Il-2 Shturmovik armored ground attack aircraft. More common unofficial\ - \ nicknames were 'Galina' (or 'Galya'), 'Crocodile' (Russian: \u041A\u0440\u043E\ - \u043A\u043E\u0434\u0438\u043B, romanized: Krokodil), due to the helicopter's camouflage\ - \ scheme, and 'Drinking Glass' (Russian: \u0421\u0442\u0430\u043A\u0430\u043D, romanized:\ - \ Stakan), because of the flat glass plates that surround earlier Mi-24 variants'\ - \ cockpits. It served to a great success in the Afghanistan war, until the Taliban\ - \ where equipped with Stinger Missiles from the CIA." -lha_capable: true -cabin_size: 6 -can_carry_crates: true -introduced: 1981 -manufacturer: Mil -origin: USSR/Russia -price: 14 -role: Attack/Transport -kneeboard_units: "metric" -variants: - Mi-24P Hind-F: {} -tasks: - Air Assault: 20 - BAI: 410 - CAS: 410 - OCA/Aircraft: 410 -hit_points: 20 diff --git a/resources/units/aircraft/Mi-24V.yaml b/resources/units/aircraft/Mi-24V.yaml deleted file mode 100644 index f6e1fd0d5..000000000 --- a/resources/units/aircraft/Mi-24V.yaml +++ /dev/null @@ -1,33 +0,0 @@ -class: Helicopter -always_keeps_gun: true -description: - "The Mil Mi-24 (Russian: \u041C\u0438\u043B\u044C \u041C\u0438-24; NATO\ - \ reporting name: Hind) is a large helicopter gunship, attack helicopter and low-capacity\ - \ troop transport with room for eight passengers. It is produced by Mil Moscow Helicopter\ - \ Plant and has been operated since 1972 by the Soviet Air Force and its successors,\ - \ along with 48 other nations. Soviet pilots called the Mi-24 the 'flying tank'\ - \ (Russian: \u043B\u0435\u0442\u0430\u044E\u0449\u0438\u0439 \u0442\u0430\u043D\u043A\ - , romanized: letayushchiy tank), a term used historically with the famous World\ - \ War II Soviet Il-2 Shturmovik armored ground attack aircraft. More common unofficial\ - \ nicknames were 'Galina' (or 'Galya'), 'Crocodile' (Russian: \u041A\u0440\u043E\ - \u043A\u043E\u0434\u0438\u043B, romanized: Krokodil), due to the helicopter's camouflage\ - \ scheme, and 'Drinking Glass' (Russian: \u0421\u0442\u0430\u043A\u0430\u043D, romanized:\ - \ Stakan), because of the flat glass plates that surround earlier Mi-24 variants'\ - \ cockpits. It served to a great success in the Afghanistan war, until the Taliban\ - \ where equiped with Stinger Misseles from the CIA." -lha_capable: true -cabin_size: 6 -can_carry_crates: true -introduced: 1976 -manufacturer: Mil -origin: USSR/Russia -price: 14 -role: Attack/Transport -variants: - Mi-24V Hind-E: {} -tasks: - Air Assault: 10 - BAI: 400 - CAS: 400 - OCA/Aircraft: 400 -hit_points: 16 diff --git a/resources/units/aircraft/Mi-26.yaml b/resources/units/aircraft/Mi-26.yaml deleted file mode 100644 index f217d6490..000000000 --- a/resources/units/aircraft/Mi-26.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Helicopter -cabin_size: 24 # It should have 60+ but we do not want so much for CTLD to be possible -can_carry_crates: true -price: 6 -variants: - Mi-26: null -tasks: - Air Assault: 30 - Transport: 0 -hit_points: 30 diff --git a/resources/units/aircraft/Mi-28N.yaml b/resources/units/aircraft/Mi-28N.yaml deleted file mode 100644 index 57a93af81..000000000 --- a/resources/units/aircraft/Mi-28N.yaml +++ /dev/null @@ -1,22 +0,0 @@ -class: Helicopter -cabin_size: 0 -can_carry_crates: false -always_keeps_gun: true -description: - The Mil Mi-28 (NATO reporting name 'Havoc') is a Russian all-weather, - day-night, military tandem, two-seat anti-armor attack helicopter. It is an attack - helicopter with no intended secondary transport capability, better optimized than - the Mil Mi-24 gunship for the role. It carries a single gun in an undernose barbette, - plus external loads carried on pylons beneath stub wings. -introduced: 2009 -manufacturer: Mil -origin: USSR/Russia -price: 16 -role: Attack -variants: - Mi-28N Havoc: {} -tasks: - BAI: 420 - CAS: 420 - OCA/Aircraft: 420 -hit_points: 15 diff --git a/resources/units/aircraft/Mi-8MT.yaml b/resources/units/aircraft/Mi-8MT.yaml deleted file mode 100644 index 982bc90fe..000000000 --- a/resources/units/aircraft/Mi-8MT.yaml +++ /dev/null @@ -1,24 +0,0 @@ -class: Helicopter -carrier_capable: true -description: - The Mil Mi-8MTV2 is an upgraded version of one of the most widely produced - helicopters in history and a combat transport and fire support veteran of countless - operations around the world. -introduced: 1981 -lha_capable: true -cabin_size: 12 -can_carry_crates: true -manufacturer: Mil -origin: USSR/Russia -price: 5 -role: Transport/Light Attack -variants: - Mi-8MTV2 Hip: {} -kneeboard_units: "metric" -tasks: - Air Assault: 40 - BAI: 390 - CAS: 390 - OCA/Aircraft: 390 - Transport: 10 -hit_points: 18 diff --git a/resources/units/aircraft/MiG-15bis.yaml b/resources/units/aircraft/MiG-15bis.yaml deleted file mode 100644 index 5aeaf23f0..000000000 --- a/resources/units/aircraft/MiG-15bis.yaml +++ /dev/null @@ -1,36 +0,0 @@ -always_keeps_gun: true -description: - Developed in the years immediately following World War II, the MiG-15bis - was a first-generation jet fighter designed by the Mikoyan-Gurevich design bureau - of the Soviet Union. The MiG-15bis is a single engine, swept-wing jet that saw over - 15,000 copies produced. The MiG-15 gained fame in the skies over Korea where it - battled the F-86 Sabre and other allied aircraft. It proved an excellent match to - the Sabre, and it often came down to the skill of the pilot that determined who - made it home and who was left dangling from a parachute. Having an excellent thrust-to-weight - ratio and good climbing characteristics, the MiG-15bis was also armed with two NR-23 - 23mm cannons and a single, powerful N-37 37mm cannon. Not surprisingly, it is considered - by many as one of the deadliest fighters of the era. -introduced: 1950 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 8 -role: Fighter -gunfighter: true -variants: - MiG-15bis Fagot: {} -radios: - intra_flight: RSI-6K HF - inter_flight: RSI-6K HF -kneeboard_units: "metric" -tasks: - BAI: 360 - BARCAP: 140 - CAS: 360 - Escort: 140 - Fighter sweep: 140 - Intercept: 140 - OCA/Aircraft: 360 - OCA/Runway: 210 - Strike: 210 - TARCAP: 140 -hit_points: 15 diff --git a/resources/units/aircraft/MiG-19P.yaml b/resources/units/aircraft/MiG-19P.yaml deleted file mode 100644 index 0816f992b..000000000 --- a/resources/units/aircraft/MiG-19P.yaml +++ /dev/null @@ -1,47 +0,0 @@ -always_keeps_gun: true -description: - "The MiG-19P Farmer was designed by the legendary Mikoyan Design Bureau\ - \ in the Early 1950\u2019s. The MiG-19 fighter was the Soviet Union\u2019s first\ - \ true supersonic Interceptor that could exceed Mach 1 in level flight.\n\nDesigned\ - \ to take on enemy fighters and bombers at any time of day or night and in any weather\ - \ condition, the Farmer was equipped with the RP-5 lzumrud radar in the nose and\ - \ armed with two NR-30 30mm cannons in the wing roots. The Farmer is also able to\ - \ carry an array of ground attack weapons that includes S-5M rockets and various\ - \ general-purpose bombs. It is a lethal interceptor with conventional ground attack\ - \ capabilities." -introduced: 1955 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 10 -role: Fighter -gunfighter: true -variants: - J-6A: - introduced: 1962 - manufacturer: Shenyang - origin: China - MiG-19P Farmer-B: {} -radios: - intra_flight: RSIU-4V - inter_flight: RSIU-4V - channels: - type: farmer - namer: single -kneeboard_units: "metric" -# default_overrides: -# ADF_FAR_Frequency: 625 -# ADF_NEAR_Frequency: 303 -# ADF_Selected_Frequency: 1 -# MissileToneVolume: 5 -# MountSIRENA: false -# NAV_Initial_Hdg: 0 -tasks: - BAI: 370 - BARCAP: 170 - CAS: 370 - Escort: 170 - Fighter sweep: 170 - Intercept: 170 - OCA/Aircraft: 370 - TARCAP: 170 -hit_points: 18 diff --git a/resources/units/aircraft/MiG-21Bis.yaml b/resources/units/aircraft/MiG-21Bis.yaml deleted file mode 100644 index a3f2b4382..000000000 --- a/resources/units/aircraft/MiG-21Bis.yaml +++ /dev/null @@ -1,42 +0,0 @@ -description: - The MiG-21bis is a delta wing, supersonic, fighter-interceptor jet aircraft. - Much like the AK-47 became the everyman's rifle, the MiG-21 has been operated by - more than 40 countries worldwide, and has enjoyed the longest production run of - any modern jet fighter to date. The MiG-21, in all of its variants, has fought in - wars stretching all the way from the Vietnam War in the 1960's to the modern day - Syrian Civil War. Owing to its unique blend of versatility, ruggedness and maintainability, - the MiG-21 remains in active service to this very day. -introduced: 1972 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 12 -role: Fighter -max_range: 200 -gunfighter: true -variants: - J-7B: - introduced: 1992 - manufacturer: Chengdu - origin: China - MiG-21bis Fishbed-N: {} -radios: - intra_flight: RSIU-5V - inter_flight: RSIU-5V - channels: - type: common - namer: single - intra_flight_radio_index: 1 - inter_flight_radio_index: 1 -kneeboard_units: "metric" -tasks: - BAI: 520 - BARCAP: 350 - CAS: 520 - Escort: 350 - Fighter sweep: 350 - Intercept: 350 - OCA/Aircraft: 520 - OCA/Runway: 220 - Strike: 220 - TARCAP: 350 -hit_points: 20 diff --git a/resources/units/aircraft/MiG-23MLD.yaml b/resources/units/aircraft/MiG-23MLD.yaml deleted file mode 100644 index 593dcd952..000000000 --- a/resources/units/aircraft/MiG-23MLD.yaml +++ /dev/null @@ -1,28 +0,0 @@ -description: - "The Mikoyan-Gurevich MiG-23 (Russian: \u041C\u0438\u043A\u043E\u044F\ - \u043D \u0438 \u0413\u0443\u0440\u0435\u0432\u0438\u0447 \u041C\u0438\u0413-23;\ - \ NATO reporting name: Flogger) is a variable-geometry fighter aircraft, designed\ - \ by the Mikoyan-Gurevich design bureau in the Soviet Union. It is a third-generation\ - \ jet fighter, the world's most-produced variable-geometry aircraft, along with\ - \ similar Soviet aircraft such as the Su-17 'Fitter'. It was the first Soviet fighter\ - \ to field a look-down/shoot-down radar, the RP-23 Sapfir, and one of the first\ - \ to be armed with beyond-visual-range missiles. Production started in 1969 and\ - \ reached large numbers with over 5,000 aircraft built, making it the most produced\ - \ variable-sweep wing aircraft in history. Today the MiG-23 remains in limited service\ - \ with some export customers." -introduced: 1982 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 12 -role: Fighter -variants: - MiG-23ML Flogger-G: - introduced: 1981 - MiG-23MLD Flogger-K: {} -tasks: - BARCAP: 360 - Escort: 360 - Fighter sweep: 360 - Intercept: 360 - TARCAP: 360 -hit_points: 16 diff --git a/resources/units/aircraft/MiG-25PD.yaml b/resources/units/aircraft/MiG-25PD.yaml deleted file mode 100644 index 859e425d9..000000000 --- a/resources/units/aircraft/MiG-25PD.yaml +++ /dev/null @@ -1,37 +0,0 @@ -description: - "The Mikoyan-Gurevich MiG-25 (Russian: \u041C\u0438\u043A\u043E\u044F\ - \u043D \u0438 \u0413\u0443\u0440\u0435\u0432\u0438\u0447 \u041C\u0438\u0413-25;\ - \ NATO reporting name: Foxbat) is a supersonic interceptor and reconnaissance aircraft\ - \ that was among the fastest military aircraft to enter service. It was designed\ - \ by the Soviet Union's Mikoyan-Gurevich bureau and is one of the few combat aircraft\ - \ built primarily using stainless steel. It was the last plane designed by Mikhail\ - \ Gurevich before his retirement. The first prototype flew in 1964, and the aircraft\ - \ entered service in 1970. The MiG-25 was theoretically capable of a maximum speed\ - \ exceeding Mach 3 and a ceiling of 27 km (89,000 ft). Its high speed was problematic:\ - \ although sufficient thrust was available to reach Mach 3.2, a limit of Mach 2.83\ - \ had to be imposed as the engines tended to overspeed and overheat at higher air\ - \ speeds, possibly damaging them beyond repair. The MiG-25 features powerful radar\ - \ and four air-to-air missiles. When first seen in reconnaissance photography, the\ - \ large wings suggested an enormous and highly maneuverable fighter, at a time when\ - \ U.S. design theories were also evolving towards higher maneuverability due to\ - \ combat performance in the Vietnam War. The appearance of the MiG-25 sparked serious\ - \ concern in the West and prompted dramatic increases in performance for the McDonnell\ - \ Douglas F-15 Eagle, then under development in the late 1960s. The capabilities\ - \ of the MiG-25 were better understood by the west in 1976 when Soviet pilot Viktor\ - \ Belenko defected in a MiG-25 to the United States via Japan. It turned out that\ - \ the aircraft's weight necessitated its large wings." -introduced: 1979 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 17 -role: Interceptor -max_range: 500 -variants: - MiG-25PD Foxbat-E: {} -tasks: - BARCAP: 390 - Escort: 390 - Fighter sweep: 390 - Intercept: 390 - TARCAP: 390 -hit_points: 24 diff --git a/resources/units/aircraft/MiG-25RBT.yaml b/resources/units/aircraft/MiG-25RBT.yaml deleted file mode 100644 index 2864ea136..000000000 --- a/resources/units/aircraft/MiG-25RBT.yaml +++ /dev/null @@ -1,32 +0,0 @@ -description: - "The Mikoyan-Gurevich MiG-25 (Russian: \u041C\u0438\u043A\u043E\u044F\ - \u043D \u0438 \u0413\u0443\u0440\u0435\u0432\u0438\u0447 \u041C\u0438\u0413-25;\ - \ NATO reporting name: Foxbat) is a supersonic interceptor and reconnaissance aircraft\ - \ that was among the fastest military aircraft to enter service. It was designed\ - \ by the Soviet Union's Mikoyan-Gurevich bureau and is one of the few combat aircraft\ - \ built primarily using stainless steel. It was the last plane designed by Mikhail\ - \ Gurevich before his retirement. The first prototype flew in 1964, and the aircraft\ - \ entered service in 1970. The MiG-25 was theoretically capable of a maximum speed\ - \ exceeding Mach 3 and a ceiling of 27 km (89,000 ft). Its high speed was problematic:\ - \ although sufficient thrust was available to reach Mach 3.2, a limit of Mach 2.83\ - \ had to be imposed as the engines tended to overspeed and overheat at higher air\ - \ speeds, possibly damaging them beyond repair. The MiG-25 features powerful radar\ - \ and four air-to-air missiles. When first seen in reconnaissance photography, the\ - \ large wings suggested an enormous and highly maneuverable fighter, at a time when\ - \ U.S. design theories were also evolving towards higher maneuverability due to\ - \ combat performance in the Vietnam War. The appearance of the MiG-25 sparked serious\ - \ concern in the West and prompted dramatic increases in performance for the McDonnell\ - \ Douglas F-15 Eagle, then under development in the late 1960s. The capabilities\ - \ of the MiG-25 were better understood by the west in 1976 when Soviet pilot Viktor\ - \ Belenko defected in a MiG-25 to the United States via Japan. It turned out that\ - \ the aircraft's weight necessitated its large wings." -introduced: 1970 -manufacturer: Mikoyan-Gurevich -origin: USSR/Russia -price: 17 -role: Strike Fighter -max_range: 500 -variants: - MiG-25RBT Foxbat-B: {} -tasks: {} -hit_points: 24 diff --git a/resources/units/aircraft/MiG-27K.yaml b/resources/units/aircraft/MiG-27K.yaml deleted file mode 100644 index b235db181..000000000 --- a/resources/units/aircraft/MiG-27K.yaml +++ /dev/null @@ -1,28 +0,0 @@ -description: - "The Mikoyan MiG-27 (Russian: \u041C\u0438\u043A\u043E\u044F\u043D \u041C\ - \u0438\u0413-27; NATO reporting name: Flogger-D/J) is a variable-sweep ground-attack\ - \ aircraft, originally built by the Mikoyan-Gurevich design bureau in the Soviet\ - \ Union and later licence-produced in India by Hindustan Aeronautics as the Bahadur\ - \ ('Valiant'). It is based on the Mikoyan-Gurevich MiG-23 fighter aircraft, but\ - \ optimised for air-to-ground attack. Unlike the MiG-23, the MiG-27 did not have\ - \ widespread use outside Russia, as most countries opted for the Mikoyan-Gurevich\ - \ MiG-23BN and Sukhoi Su-22 instead. It remains in service only with the Kazakh\ - \ Air Forces in the ground attack role. All Russian, Indian and Ukrainian MiG-27s\ - \ have been retired." -introduced: 1975 -manufacturer: Mikoyan -origin: USSR/Russia -price: 15 -role: Attack -variants: - MiG-27K Flogger-J2: {} -tasks: - BAI: 540 - CAS: 540 - DEAD: 290 - OCA/Aircraft: 540 - OCA/Runway: 230 - SEAD: 10 - SEAD Escort: 10 - Strike: 230 -hit_points: 18 diff --git a/resources/units/aircraft/MiG-29A.yaml b/resources/units/aircraft/MiG-29A.yaml deleted file mode 100644 index a42168c3d..000000000 --- a/resources/units/aircraft/MiG-29A.yaml +++ /dev/null @@ -1,43 +0,0 @@ -description: - 'The MiG-29 "Fulcrum" is a Russian-designed, twin-engine, supersonic - fighter. First operational in the early 1980s, the Fulcrum is a "light weight" fighter, - comparable to the American F/A-18 Hornet and F-16. Designed to work in conjunction - with the larger Su-27 Flanker, the MiG-29 is armed with an internal 30mm cannon - and both infrared and radar guided air-to-air missiles. For air-to-ground tasks, - the MiG-29 can be armed with a large array of unguided bombs and rockets. - - - In addition to a sophisticated pulse doppler radar, the MiG-29 is also equipped - with a passive Infrared Search and Track (IRST) sensor that allows the Fulcrum to - detect and target enemy aircraft just based on target infrared emissions. This allows - the MiG-29 to make stealthy attacks with no warning! - - - The Fulcrum is a highly-maneuverable fighter in a dogfight, and when paired with - the helmet mounted sight and the AA-11 "Archer" air-to-air missile, it is a very - lethal adversary. - - - The MiG-29 has also been widely exported and has served in many countries that include - Germany, Iran, Ukraine, and Poland.' -introduced: 1983 -manufacturer: Mikoyan -origin: USSR/Russia -price: 15 -role: Multirole Fighter -max_range: 150 -variants: - MiG-29A Fulcrum-A: {} -kneeboard_units: "metric" -tasks: - BAI: 530 - BARCAP: 370 - CAS: 530 - Escort: 370 - Fighter sweep: 370 - Intercept: 370 - OCA/Aircraft: 530 - OCA/Runway: 410 - Strike: 410 - TARCAP: 370 -hit_points: 16 diff --git a/resources/units/aircraft/MiG-29G.yaml b/resources/units/aircraft/MiG-29G.yaml deleted file mode 100644 index 6d3de68ce..000000000 --- a/resources/units/aircraft/MiG-29G.yaml +++ /dev/null @@ -1,40 +0,0 @@ -description: - 'The MiG-29 "Fulcrum" is a Russian-designed, twin-engine, supersonic - fighter. First operational in the early 1980s, the Fulcrum is a "light weight" fighter, - comparable to the American F/A-18 Hornet and F-16. Designed to work in conjunction - with the larger Su-27 Flanker, the MiG-29 is armed with an internal 30mm cannon - and both infrared and radar guided air-to-air missiles. For air-to-ground tasks, - the MiG-29 can be armed with a large array of unguided bombs and rockets. - - - In addition to a sophisticated pulse doppler radar, the MiG-29 is also equipped - with a passive Infrared Search and Track (IRST) sensor that allows the Fulcrum to - detect and target enemy aircraft just based on target infrared emissions. This allows - the MiG-29 to make stealthy attacks with no warning! - - - The Fulcrum is a highly-maneuverable fighter in a dogfight, and when paired with - the helmet mounted sight and the AA-11 "Archer" air-to-air missile, it is a very - lethal adversary. - - - The MiG-29 has also been widely exported and has served in many countries that include - Germany, Iran, Ukraine, and Poland.' -introduced: 1993 -manufacturer: Mikoyan -origin: USSR/Russia -price: 18 -role: Multirole Fighter -max_range: 150 -variants: - MiG-29G Fulcrum-A: {} -kneeboard_units: "metric" -tasks: - BARCAP: 380 - Escort: 380 - Fighter sweep: 380 - Intercept: 380 - OCA/Runway: 420 - Strike: 420 - TARCAP: 380 -hit_points: 16 diff --git a/resources/units/aircraft/MiG-29S.yaml b/resources/units/aircraft/MiG-29S.yaml deleted file mode 100644 index fb6ebea8b..000000000 --- a/resources/units/aircraft/MiG-29S.yaml +++ /dev/null @@ -1,43 +0,0 @@ -description: - 'The MiG-29 "Fulcrum" is a Russian-designed, twin-engine, supersonic - fighter. First operational in the early 1980s, the Fulcrum is a "light weight" fighter, - comparable to the American F/A-18 Hornet and F-16. Designed to work in conjunction - with the larger Su-27 Flanker, the MiG-29 is armed with an internal 30mm cannon - and both infrared and radar guided air-to-air missiles. For air-to-ground tasks, - the MiG-29 can be armed with a large array of unguided bombs and rockets. - - - In addition to a sophisticated pulse doppler radar, the MiG-29 is also equipped - with a passive Infrared Search and Track (IRST) sensor that allows the Fulcrum to - detect and target enemy aircraft just based on target infrared emissions. This allows - the MiG-29 to make stealthy attacks with no warning! - - - The Fulcrum is a highly-maneuverable fighter in a dogfight, and when paired with - the helmet mounted sight and the AA-11 "Archer" air-to-air missile, it is a very - lethal adversary. - - - The MiG-29 has also been widely exported and has served in many countries that include - Germany, Iran, Ukraine, and Poland.' -introduced: 1983 -manufacturer: Mikoyan -origin: USSR/Russia -price: 19 -role: Multirole Fighter -max_range: 150 -variants: - MiG-29S Fulcrum-C: {} -kneeboard_units: "metric" -tasks: - BAI: 550 - BARCAP: 470 - CAS: 550 - Escort: 470 - Fighter sweep: 470 - Intercept: 470 - OCA/Aircraft: 550 - OCA/Runway: 430 - Strike: 430 - TARCAP: 470 -hit_points: 16 diff --git a/resources/units/aircraft/MiG-31.yaml b/resources/units/aircraft/MiG-31.yaml deleted file mode 100644 index e39a791d2..000000000 --- a/resources/units/aircraft/MiG-31.yaml +++ /dev/null @@ -1,27 +0,0 @@ -description: - "The Mikoyan MiG-31 (Russian: \u041C\u0438\u043A\u043E\u044F\u043D \u041C\ - \u0438\u0413-31; NATO reporting name: Foxhound) is a supersonic interceptor aircraft\ - \ that was developed for use by the Soviet Air Forces. The aircraft was designed\ - \ by the Mikoyan design bureau as a replacement for the earlier MiG-25 \"Foxbat\"\ - ; the MiG-31 is based on and shares design elements with the MiG-25. The MiG-31\ - \ is among the fastest combat jets in the world. It continues to be operated by\ - \ the Russian Air Force and the Kazakhstan Air Force following the end of the Cold\ - \ War and the collapse of the Soviet Union in 1991. The Russian Defence Ministry\ - \ expects the MiG-31 to remain in service until 2030 or beyond and was confirmed\ - \ in 2020 when an announcement was made to extend the service lifetime from 2,500\ - \ to 3,500 hours on the existing airframes." -introduced: 1981 -manufacturer: Mikoyan -origin: USSR/Russia -price: 24 -role: Interceptor -max_range: 800 -variants: - MiG-31 Foxhound: {} -tasks: - BARCAP: 400 - Escort: 400 - Fighter sweep: 400 - Intercept: 400 - TARCAP: 400 -hit_points: 24 diff --git a/resources/units/aircraft/Mirage 2000-5.yaml b/resources/units/aircraft/Mirage 2000-5.yaml deleted file mode 100644 index 1b2bf7e0d..000000000 --- a/resources/units/aircraft/Mirage 2000-5.yaml +++ /dev/null @@ -1,24 +0,0 @@ -description: - "The Dassault Mirage 2000 is a French multirole, single-engined, fourth-generation\ - \ jet fighter manufactured by Dassault Aviation. It was designed in the late 1970s\ - \ as a lightweight fighter to replace the Mirage III for the French Air Force (Arm\xE9\ - e de l'air). The Mirage 2000 evolved into a multirole aircraft with several variants\ - \ developed, with sales to a number of nations. It was later developed into the\ - \ Mirage 2000N and 2000D strike variants, the improved Mirage 2000-5, and several\ - \ export variants. Over 600 aircraft were built and it has been in service with\ - \ 9 nations." -introduced: 1997 -manufacturer: Dassault -origin: France -price: 18 -role: Multirole Fighter -max_range: 400 -variants: - Mirage 2000-5: {} -tasks: - BARCAP: 340 - Escort: 340 - Fighter sweep: 340 - Intercept: 340 - TARCAP: 340 -hit_points: 16 diff --git a/resources/units/aircraft/Mirage-F1B.yaml b/resources/units/aircraft/Mirage-F1B.yaml deleted file mode 100644 index fa71da40d..000000000 --- a/resources/units/aircraft/Mirage-F1B.yaml +++ /dev/null @@ -1,28 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - The French Air Force also ordered 20 Mirage F1Bs, a two-seat operational conversion trainer; - these were delivered between October 1980 and March 1983.[108] The extra seat and controls added - only 30 cm (12 in) to the length of the fuselage, but at the cost of less internal fuel capacity - and the loss of the internal cannons. -introduced: 1980 -manufacturer: Dassault -origin: France -price: 14 -role: Fighter -max_range: 200 -variants: - Mirage-F1B: {} -tasks: - BAI: 340 - BARCAP: 330 - CAS: 340 - Escort: 330 - Fighter sweep: 330 - Intercept: 330 - OCA/Aircraft: 340 - OCA/Runway: 310 - Strike: 310 - TARCAP: 330 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1BE.yaml b/resources/units/aircraft/Mirage-F1BE.yaml deleted file mode 100644 index 5daa691c2..000000000 --- a/resources/units/aircraft/Mirage-F1BE.yaml +++ /dev/null @@ -1,25 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - Mirage F1B for Spain, local designation CE.14A. Six delivered 1980–1981. -introduced: 1980 -manufacturer: Dassault -origin: France -price: 14 -role: Fighter -max_range: 200 -variants: - Mirage-F1BE: {} -tasks: - BAI: 330 - BARCAP: 320 - CAS: 330 - Escort: 320 - Fighter sweep: 320 - Intercept: 320 - OCA/Aircraft: 330 - OCA/Runway: 300 - Strike: 300 - TARCAP: 320 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1C-200.yaml b/resources/units/aircraft/Mirage-F1C-200.yaml deleted file mode 100644 index edf514fe2..000000000 --- a/resources/units/aircraft/Mirage-F1C-200.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - Designation for F1Cs fitted with refuelling probe. -introduced: 1973 -manufacturer: Dassault -origin: France -price: 14 -role: Fighter -max_range: 200 -variants: - Mirage-F1C-200: {} -tasks: - BARCAP: 260 - Escort: 260 - Fighter sweep: 260 - Intercept: 260 - TARCAP: 260 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1CE.yaml b/resources/units/aircraft/Mirage-F1CE.yaml deleted file mode 100644 index b79ab9a00..000000000 --- a/resources/units/aircraft/Mirage-F1CE.yaml +++ /dev/null @@ -1,34 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - Export version of the Mirage F1C for Spain, with local designation C.14A. 45 purchased in three batches, - delivered between 1975 and 1981. -introduced: 1975 -manufacturer: Dassault -origin: France -price: 14 -role: Fighter -max_range: 200 -variants: - Mirage-F1CE: {} -radios: - intra_flight: UHF TRAP 137B - inter_flight: V/UHF TRAP 136 - channels: - type: common - namer: mirage-f1ce - intra_flight_radio_index: 2 - inter_flight_radio_index: 1 -tasks: - BAI: 320 - BARCAP: 310 - CAS: 320 - Escort: 310 - Fighter sweep: 310 - Intercept: 310 - OCA/Aircraft: 320 - OCA/Runway: 290 - Strike: 290 - TARCAP: 310 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1CT.yaml b/resources/units/aircraft/Mirage-F1CT.yaml deleted file mode 100644 index 159d7f1df..000000000 --- a/resources/units/aircraft/Mirage-F1CT.yaml +++ /dev/null @@ -1,35 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - The Mirage F1CT is a ground attack version of the Mirage F1C-200. - Following their replacement in the air defence role by the Mirage 2000, - the French Air Force had a number of surplus Mirage F1C-200s, and in 1988 it launched a conversion - programme to turn these aircraft into interim ground attack aircraft to replace elderly Mirage IIIEs - and Mirage 5s. The Mirage F1CT program brought the avionics of the F1C up to the standard of the F1CR, - with the radar upgraded with the additional air-to-ground modes of the Cyrano IVM-R, - an improved navigation/attack system fitted, with a laser rangefinder fitted under the nose. - It was fitted with new Mk 10 ejection seats, while improved radar detection and warning devices, - chaff/flare dispensers, and secure radios were also added. It gained the ability to carry a variety - of air-to-ground weapons, including rockets, cluster bombs and laser-guided bombs, - while retaining the F1C's air-to-air armament. -introduced: 1988 -manufacturer: Dassault -origin: France -price: 15 -role: Multirole Fighter -max_range: 200 -variants: - Mirage-F1CT: {} -tasks: - BAI: 270 - BARCAP: 250 - CAS: 270 - Escort: 250 - Fighter sweep: 250 - Intercept: 250 - OCA/Aircraft: 270 - OCA/Runway: 240 - Strike: 240 - TARCAP: 250 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1EE.yaml b/resources/units/aircraft/Mirage-F1EE.yaml deleted file mode 100644 index 99488379f..000000000 --- a/resources/units/aircraft/Mirage-F1EE.yaml +++ /dev/null @@ -1,26 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - The F1E is a single-seat all-weather multi-role fighter and ground-attack aircraft. - The F1EE is the export version of the Mirage F1E for Spain. 22 built. -introduced: 1975 # http://www.airvectors.net/avmirf1.html -manufacturer: Dassault -origin: France -price: 14 -role: Multirole Fighter -max_range: 200 -variants: - Mirage-F1EE: {} -tasks: - BAI: 310 - BARCAP: 300 - CAS: 310 - Escort: 300 - Fighter sweep: 300 - Intercept: 300 - OCA/Aircraft: 310 - OCA/Runway: 280 - Strike: 280 - TARCAP: 300 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1EQ.yaml b/resources/units/aircraft/Mirage-F1EQ.yaml deleted file mode 100644 index 528473640..000000000 --- a/resources/units/aircraft/Mirage-F1EQ.yaml +++ /dev/null @@ -1,25 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - Export version of the Mirage F1E for Iraq. Single-seat all-weather multi-role fighter and ground-attack aircraft. -introduced: 1980 -manufacturer: Dassault -origin: France -price: 14 -role: Multirole Fighter -max_range: 200 -variants: - Mirage-F1EQ: {} -tasks: - BAI: 300 - BARCAP: 290 - CAS: 300 - Escort: 290 - Fighter sweep: 290 - Intercept: 290 - OCA/Aircraft: 300 - OCA/Runway: 270 - Strike: 270 - TARCAP: 290 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1M-CE.yaml b/resources/units/aircraft/Mirage-F1M-CE.yaml deleted file mode 100644 index 979d4db18..000000000 --- a/resources/units/aircraft/Mirage-F1M-CE.yaml +++ /dev/null @@ -1,30 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - The F1M upgrade was applied to 48 Spanish F1CE/EE and four F1EDA trainers. - The prototype F1M flew in April 1998, and CASA delivered the remainder between March 1999 and 15 March 2001. - The project included a revised cockpit with colour LCDs and a Smart HUD from Sextant Avionique, - a Sextant inertial navigation system with GPS interface; NATO-compatible Have Quick 2 secure communications; - Mode 4 digital IFF; a defensive aids suite; and flight recorders. The radar was upgraded to Cyrano IVM standard, - adding sea search and air to ground ranging modes. -introduced: 1998 -manufacturer: Dassault -origin: France -price: 16 -role: Multirole Fighter -max_range: 200 -variants: - Mirage-F1M-CE: {} -tasks: - BAI: 290 - BARCAP: 280 - CAS: 290 - Escort: 280 - Fighter sweep: 280 - Intercept: 280 - OCA/Aircraft: 290 - OCA/Runway: 260 - Strike: 260 - TARCAP: 280 -hit_points: 18 diff --git a/resources/units/aircraft/Mirage-F1M-EE.yaml b/resources/units/aircraft/Mirage-F1M-EE.yaml deleted file mode 100644 index b9b3c5160..000000000 --- a/resources/units/aircraft/Mirage-F1M-EE.yaml +++ /dev/null @@ -1,30 +0,0 @@ -description: # From wikipedia - The Dassault Mirage F1 is a French fighter and attack aircraft designed and manufactured - by Dassault Aviation. It was developed as a successor to the popular Mirage III family. - - The F1M upgrade was applied to 48 Spanish F1CE/EE and four F1EDA trainers. - The prototype F1M flew in April 1998, and CASA delivered the remainder between March 1999 and 15 March 2001. - The project included a revised cockpit with colour LCDs and a Smart HUD from Sextant Avionique, - a Sextant inertial navigation system with GPS interface; NATO-compatible Have Quick 2 secure communications; - Mode 4 digital IFF; a defensive aids suite; and flight recorders. The radar was upgraded to Cyrano IVM standard, - adding sea search and air to ground ranging modes. -introduced: 1998 -manufacturer: Dassault -origin: France -price: 16 -role: Multirole Fighter -max_range: 200 -variants: - Mirage-F1M-EE: {} -tasks: - BAI: 280 - BARCAP: 270 - CAS: 280 - Escort: 270 - Fighter sweep: 270 - Intercept: 270 - OCA/Aircraft: 280 - OCA/Runway: 250 - Strike: 250 - TARCAP: 270 -hit_points: 18 diff --git a/resources/units/aircraft/MosquitoFBMkVI.yaml b/resources/units/aircraft/MosquitoFBMkVI.yaml deleted file mode 100644 index b162d0766..000000000 --- a/resources/units/aircraft/MosquitoFBMkVI.yaml +++ /dev/null @@ -1,27 +0,0 @@ -description: The de Havilland DH.98 Mosquito is a British twin-engined, shoulder-winged multirole combat aircraft, introduced during the Second World War. -introduced: 1941 -manufacturer: De Havilland Aircraft Co -origin: UK -price: 6 -role: Light Bomber, Fighter Bomber, Night Fighter, Maritime Strike Aircraft, Photo Recon Aircraft -variants: - MosquitoFBMkVI: {} -kneeboard_units: "imperial" -# default_overrides: -# Flare_Gun: 1 -# ResinLights: 0.15 -# SoloFlight: false -tasks: - Anti-ship: 20 - BAI: 70 - BARCAP: 70 - CAS: 70 - DEAD: 30 - Escort: 70 - Fighter sweep: 70 - Intercept: 70 - OCA/Aircraft: 70 - OCA/Runway: 30 - Strike: 30 - TARCAP: 70 -hit_points: 48 diff --git a/resources/units/aircraft/OH-58D.yaml b/resources/units/aircraft/OH-58D.yaml deleted file mode 100644 index e01c80035..000000000 --- a/resources/units/aircraft/OH-58D.yaml +++ /dev/null @@ -1,27 +0,0 @@ -class: Helicopter -cabin_size: 0 # Can not transport troops -can_carry_crates: false # Can not carry crates -carrier_capable: true -description: - The Bell OH-58 Kiowa is a family of single-engine, single-rotor, military - helicopters used for observation, utility, and direct fire support. Bell Helicopter - manufactured the OH-58 for the United States Army based on its Model 206A JetRanger - helicopter. The OH-58 was in continuous U.S. Army service from 1969 to 2017, when - it was replaced in these roles by the Boeing AH-64 Apache and Eurocopter UH-72 Lakota. - The latest model, the OH-58D Kiowa Warrior, is primarily operated in an armed reconnaissance - role in support of ground troops. The OH-58 has been exported to Austria, Canada, - Croatia, the Dominican Republic, Taiwan, Saudi Arabia, and Greece. It has also been - produced under license in Australia. -introduced: 1983 -lha_capable: true -manufacturer: Bell -origin: USA -price: 6 -role: Light Attack/Forward Air Control -variants: - OH-58D Kiowa Warrior: {} -tasks: - BAI: 470 - CAS: 470 - OCA/Aircraft: 470 -hit_points: 12 diff --git a/resources/units/aircraft/P-47D-30.yaml b/resources/units/aircraft/P-47D-30.yaml deleted file mode 100644 index 9488f3bf0..000000000 --- a/resources/units/aircraft/P-47D-30.yaml +++ /dev/null @@ -1,47 +0,0 @@ -always_keeps_gun: true -description: - "The P-47 Thunderbolt, nicknamed the Jug, served the United States Army - Air Forces (USAAF) in World War II with distinction. In total 15,636 were built - between 1941 and 1945. France, the United Kingdom, the Soviet Union, Mexico and - Brazil also operated the P-47. It was armed with an impressive eight .50-caliber - machine guns with 425 rounds per gun. In addition the Jug was armed with bombs and - rockets and it excelled in the ground attack role. The P-47 also served in the bomber - escort role before the introduction of the P-51 Mustang which had longer range. - - - Powered by an R-2800-59 Double Wasp turbocharged radial engine, the aircraft enjoyed - exceptional power and durability. The Jug substantial weight gave it tremendous - dive speed acceleration but the aircraft suffered from quite low Mach limits and - hence the aircraft was equipped with dive flaps to avoid dangerous effects of compressibility. - The bubble canopy of the D version of the P-47 provided excellent all round visibility." -introduced: 1944 -manufacturer: Republic -origin: USA -price: 5 -role: Fighter-Bomber -gunfighter: true -variants: - P-47D-30 Thunderbolt (Late): {} - Thunderbolt Mk.II (Mid): {} -radios: - intra_flight: SCR522 - inter_flight: SCR522 - channels: - type: SCR-522 - namer: SCR-522 -kneeboard_units: "imperial" -# default_overrides: -# WaterTankContents: 1 -tasks: - BAI: 120 - BARCAP: 30 - CAS: 120 - DEAD: 90 - Escort: 30 - Fighter sweep: 30 - Intercept: 30 - OCA/Aircraft: 120 - OCA/Runway: 80 - Strike: 80 - TARCAP: 30 -hit_points: 24 diff --git a/resources/units/aircraft/P-47D-30bl1.yaml b/resources/units/aircraft/P-47D-30bl1.yaml deleted file mode 100644 index 7edc0e630..000000000 --- a/resources/units/aircraft/P-47D-30bl1.yaml +++ /dev/null @@ -1,47 +0,0 @@ -always_keeps_gun: true -description: - "The P-47 Thunderbolt, nicknamed the Jug, served the United States Army - Air Forces (USAAF) in World War II with distinction. In total 15,636 were built - between 1941 and 1945. France, the United Kingdom, the Soviet Union, Mexico and - Brazil also operated the P-47. It was armed with an impressive eight .50-caliber - machine guns with 425 rounds per gun. In addition the Jug was armed with bombs and - rockets and it excelled in the ground attack role. The P-47 also served in the bomber - escort role before the introduction of the P-51 Mustang which had longer range. - - - Powered by an R-2800-59 Double Wasp turbocharged radial engine, the aircraft enjoyed - exceptional power and durability. The Jug substantial weight gave it tremendous - dive speed acceleration but the aircraft suffered from quite low Mach limits and - hence the aircraft was equipped with dive flaps to avoid dangerous effects of compressibility. - The bubble canopy of the D version of the P-47 provided excellent all round visibility." -introduced: 1944 -manufacturer: Republic -origin: USA -price: 5 -role: Fighter-Bomber -gunfighter: true -variants: - P-47D-30 Thunderbolt (Early): {} - Thunderbolt Mk.II (Early): {} -radios: - intra_flight: SCR522 - inter_flight: SCR522 - channels: - type: SCR-522 - namer: SCR-522 -kneeboard_units: "imperial" -# default_overrides: -# WaterTankContents: 1 -tasks: - BAI: 130 - BARCAP: 20 - CAS: 130 - DEAD: 100 - Escort: 20 - Fighter sweep: 20 - Intercept: 20 - OCA/Aircraft: 130 - OCA/Runway: 90 - Strike: 90 - TARCAP: 20 -hit_points: 24 diff --git a/resources/units/aircraft/P-47D-40.yaml b/resources/units/aircraft/P-47D-40.yaml deleted file mode 100644 index 8918214d0..000000000 --- a/resources/units/aircraft/P-47D-40.yaml +++ /dev/null @@ -1,47 +0,0 @@ -always_keeps_gun: true -description: - "The P-47 Thunderbolt, nicknamed the Jug, served the United States Army - Air Forces (USAAF) in World War II with distinction. In total 15,636 were built - between 1941 and 1945. France, the United Kingdom, the Soviet Union, Mexico and - Brazil also operated the P-47. It was armed with an impressive eight .50-caliber - machine guns with 425 rounds per gun. In addition the Jug was armed with bombs and - rockets and it excelled in the ground attack role. The P-47 also served in the bomber - escort role before the introduction of the P-51 Mustang which had longer range. - - - Powered by an R-2800-59 Double Wasp turbocharged radial engine, the aircraft enjoyed - exceptional power and durability. The Jug substantial weight gave it tremendous - dive speed acceleration but the aircraft suffered from quite low Mach limits and - hence the aircraft was equipped with dive flaps to avoid dangerous effects of compressibility. - The bubble canopy of the D version of the P-47 provided excellent all round visibility." -introduced: 1944 -manufacturer: Republic -origin: USA -price: 6 -role: Fighter-Bomber -gunfighter: true -variants: - P-47D-40 Thunderbolt: {} - Thunderbolt Mk.II (Late): {} -radios: - intra_flight: SCR522 - inter_flight: SCR522 - channels: - type: SCR-522 - namer: SCR-522 -kneeboard_units: "imperial" -# default_overrides: -# WaterTankContents: 1 -tasks: - BAI: 140 - BARCAP: 10 - CAS: 140 - DEAD: 110 - Escort: 10 - Fighter sweep: 10 - Intercept: 10 - OCA/Aircraft: 140 - OCA/Runway: 100 - Strike: 100 - TARCAP: 10 -hit_points: 24 diff --git a/resources/units/aircraft/P-51D-30-NA.yaml b/resources/units/aircraft/P-51D-30-NA.yaml deleted file mode 100644 index cd57afecb..000000000 --- a/resources/units/aircraft/P-51D-30-NA.yaml +++ /dev/null @@ -1,46 +0,0 @@ -always_keeps_gun: true -description: - The North American Aviation P-51 Mustang is an American long-range, single-seat - fighter and fighter-bomber used during World War II and the Korean War, among other - conflicts. From late 1943, P-51Bs and P-51Cs (supplemented by P-51Ds from mid-1944) - were used by the USAAF's Eighth Air Force to escort bombers in raids over Germany, - while the RAF's Second Tactical Air Force and the USAAF's Ninth Air Force used the - Merlin-powered Mustangs as fighter-bombers, roles in which the Mustang helped ensure - Allied air superiority in 1944. The P-51 was also used by Allied air forces in the - North African, Mediterranean, Italian, and Pacific theaters. During World War II, - Mustang pilots claimed to have destroyed 4,950 enemy aircraft. At the start of the - Korean War, the Mustang, by then redesignated F-51, was the main fighter of the - United States until jet fighters, including North American's F-86, took over this - role; the Mustang then became a specialized fighter-bomber. Despite the advent of - jet fighters, the Mustang remained in service with some air forces until the early - 1980s. After the Korean War, Mustangs became popular civilian warbirds and air racing - aircraft. -introduced: 1944 -manufacturer: North American -origin: USA -price: 5 -role: Fighter -gunfighter: true -variants: - Mustang Mk.IV (Late): {} - P-51D-30-NA Mustang: {} -radios: - intra_flight: SCR522 - inter_flight: SCR522 - channels: - type: SCR-522 - namer: SCR-522 -kneeboard_units: "imperial" -tasks: - BAI: 110 - BARCAP: 110 - CAS: 110 - DEAD: 80 - Escort: 110 - Fighter sweep: 110 - Intercept: 110 - OCA/Aircraft: 110 - OCA/Runway: 70 - Strike: 70 - TARCAP: 110 -hit_points: 18 diff --git a/resources/units/aircraft/P-51D.yaml b/resources/units/aircraft/P-51D.yaml deleted file mode 100644 index f99a81e8b..000000000 --- a/resources/units/aircraft/P-51D.yaml +++ /dev/null @@ -1,46 +0,0 @@ -always_keeps_gun: true -description: - The North American Aviation P-51 Mustang is an American long-range, single-seat - fighter and fighter-bomber used during World War II and the Korean War, among other - conflicts. From late 1943, P-51Bs and P-51Cs (supplemented by P-51Ds from mid-1944) - were used by the USAAF's Eighth Air Force to escort bombers in raids over Germany, - while the RAF's Second Tactical Air Force and the USAAF's Ninth Air Force used the - Merlin-powered Mustangs as fighter-bombers, roles in which the Mustang helped ensure - Allied air superiority in 1944. The P-51 was also used by Allied air forces in the - North African, Mediterranean, Italian, and Pacific theaters. During World War II, - Mustang pilots claimed to have destroyed 4,950 enemy aircraft. At the start of the - Korean War, the Mustang, by then redesignated F-51, was the main fighter of the - United States until jet fighters, including North American's F-86, took over this - role; the Mustang then became a specialized fighter-bomber. Despite the advent of - jet fighters, the Mustang remained in service with some air forces until the early - 1980s. After the Korean War, Mustangs became popular civilian warbirds and air racing - aircraft. -introduced: 1944 -manufacturer: North American -origin: USA -price: 4 -role: Fighter -gunfighter: true -variants: - Mustang Mk.IV (Early): {} - P-51D-25-NA Mustang: {} -radios: - intra_flight: SCR522 - inter_flight: SCR522 - channels: - type: SCR-522 - namer: SCR-522 -kneeboard_units: "imperial" -tasks: - BAI: 100 - BARCAP: 100 - CAS: 100 - DEAD: 70 - Escort: 100 - Fighter sweep: 100 - Intercept: 100 - OCA/Aircraft: 100 - OCA/Runway: 60 - Strike: 60 - TARCAP: 100 -hit_points: 18 diff --git a/resources/units/aircraft/RQ-1A Predator.yaml b/resources/units/aircraft/RQ-1A Predator.yaml deleted file mode 100644 index b59aa2496..000000000 --- a/resources/units/aircraft/RQ-1A Predator.yaml +++ /dev/null @@ -1,8 +0,0 @@ -price: 6 -variants: - RQ-1A Predator: null -tasks: - BAI: 0 - CAS: 0 - OCA/Aircraft: 0 -hit_points: 5 diff --git a/resources/units/aircraft/S-3B Tanker.yaml b/resources/units/aircraft/S-3B Tanker.yaml deleted file mode 100644 index df3c9d57f..000000000 --- a/resources/units/aircraft/S-3B Tanker.yaml +++ /dev/null @@ -1,29 +0,0 @@ -carrier_capable: true -description: - The Lockheed S-3 Viking is a 4-crew, twin-engine turbofan-powered jet - aircraft that was used by the U.S. Navy (USN) primarily for anti-submarine warfare. - In the late 1990s, the S-3B's mission focus shifted to surface warfare and aerial - refueling. The Viking also provided electronic warfare and surface surveillance - capabilities to a carrier battle group. A carrier-based, subsonic, all-weather, - long-range, multi-mission aircraft, it carried automated weapon systems and was - capable of extended missions with in-flight refueling. Because of its characteristic - sound, it was nicknamed the "War Hoover" after the vacuum cleaner brand. The S-3 - was phased out from front-line fleet service aboard aircraft carriers in January - 2009, with its missions taken over by aircraft like the P-3C Orion, P-8 Poseidon, - Sikorsky SH-60 Seahawk and Boeing F/A-18E/F Super Hornet -introduced: 1984 -manufacturer: Lockheed -origin: USA -price: 20 -max_group_size: 1 -role: Carrier-based Tanker -max_range: 1000 -patrol: - # ~265 knots IAS. - speed: 320 - altitude: 12000 -variants: - S-3B Tanker: {} -tasks: - Refueling: 0 -hit_points: 25 diff --git a/resources/units/aircraft/S-3B.yaml b/resources/units/aircraft/S-3B.yaml deleted file mode 100644 index afebb3890..000000000 --- a/resources/units/aircraft/S-3B.yaml +++ /dev/null @@ -1,29 +0,0 @@ -carrier_capable: true -description: - The Lockheed S-3 Viking is a 4-crew, twin-engine turbofan-powered jet - aircraft that was used by the U.S. Navy (USN) primarily for anti-submarine warfare. - In the late 1990s, the S-3B's mission focus shifted to surface warfare and aerial - refueling. The Viking also provided electronic warfare and surface surveillance - capabilities to a carrier battle group. A carrier-based, subsonic, all-weather, - long-range, multi-mission aircraft, it carried automated weapon systems and was - capable of extended missions with in-flight refueling. Because of its characteristic - sound, it was nicknamed the "War Hoover" after the vacuum cleaner brand. The S-3 - was phased out from front-line fleet service aboard aircraft carriers in January - 2009, with its missions taken over by aircraft like the P-3C Orion, P-8 Poseidon, - Sikorsky SH-60 Seahawk and Boeing F/A-18E/F Super Hornet -introduced: 1984 -manufacturer: Lockheed -origin: USA -price: 10 -role: Carrier-based Attack -variants: - S-3B Viking: {} -tasks: - Anti-ship: 50 - BAI: 570 - CAS: 570 - DEAD: 200 - OCA/Aircraft: 570 - OCA/Runway: 370 - Strike: 370 -hit_points: 25 diff --git a/resources/units/aircraft/SA342L.yaml b/resources/units/aircraft/SA342L.yaml deleted file mode 100644 index 1b1429d65..000000000 --- a/resources/units/aircraft/SA342L.yaml +++ /dev/null @@ -1,27 +0,0 @@ -class: Helicopter -carrier_capable: true -description: - "The SA342 Gazelle is a light scout/attack and transport helicopter.\ - \ It was introduced in 1968 as a result of cooperation between A\xE9rospatiale and\ - \ Westland Aircraft. Operated by 23 countries, the Gazelle has served in combat\ - \ operations across the world including the 1991 Gulf War, 1982 Lebanon War, Syria,\ - \ and other conflicts.\n\nThe Gazelle is powered by a single turbine engine that\ - \ is connected to three glass-fiber reinforced plastic main rotor blades with a\ - \ bearingless main rotor developed by B\xF6lkow GmbH. It is also the first helicopter\ - \ which features the famous Fenestron tail rotor." -introduced: 1977 -lha_capable: true -cabin_size: 2 -can_carry_crates: false -manufacturer: "A\xE9rospatiale" -origin: France -price: 5 -role: Light Attack -variants: - SA 342L Gazelle: {} -kneeboard_units: "metric" -tasks: - BAI: 450 - CAS: 450 - OCA/Aircraft: 450 -hit_points: 18 diff --git a/resources/units/aircraft/SA342M.yaml b/resources/units/aircraft/SA342M.yaml deleted file mode 100644 index f1ac0df92..000000000 --- a/resources/units/aircraft/SA342M.yaml +++ /dev/null @@ -1,30 +0,0 @@ -class: Helicopter -carrier_capable: true -description: - "The SA342 Gazelle is a light scout/attack and transport helicopter.\ - \ It was introduced in 1968 as a result of cooperation between A\xE9rospatiale and\ - \ Westland Aircraft. Operated by 23 countries, the Gazelle has served in combat\ - \ operations across the world including the 1991 Gulf War, 1982 Lebanon War, Syria,\ - \ and other conflicts.\n\nThe Gazelle is powered by a single turbine engine that\ - \ is connected to three glass-fiber reinforced plastic main rotor blades with a\ - \ bearingless main rotor developed by B\xF6lkow GmbH. It is also the first helicopter\ - \ which features the famous Fenestron tail rotor." -introduced: 1977 -lha_capable: true -cabin_size: 2 -can_carry_crates: false -manufacturer: "A\xE9rospatiale" -origin: France -price: 8 -role: Light Attack -variants: - Gazelle AH.1: - introduced: 1974 - manufacturer: Westland - SA 342M Gazelle: {} -kneeboard_units: "metric" -tasks: - BAI: 460 - CAS: 460 - OCA/Aircraft: 460 -hit_points: 18 diff --git a/resources/units/aircraft/SA342Minigun.yaml b/resources/units/aircraft/SA342Minigun.yaml deleted file mode 100644 index 02f6c78d8..000000000 --- a/resources/units/aircraft/SA342Minigun.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: Helicopter -price: 4 -cabin_size: 2 -can_carry_crates: false -variants: - SA342Minigun: null -kneeboard_units: "metric" -tasks: {} -hit_points: 18 diff --git a/resources/units/aircraft/SA342Mistral.yaml b/resources/units/aircraft/SA342Mistral.yaml deleted file mode 100644 index 407ab1488..000000000 --- a/resources/units/aircraft/SA342Mistral.yaml +++ /dev/null @@ -1,24 +0,0 @@ -class: Helicopter -carrier_capable: true -description: - "The SA342 Gazelle is a light scout/attack and transport helicopter.\ - \ It was introduced in 1968 as a result of cooperation between A\xE9rospatiale and\ - \ Westland Aircraft. Operated by 23 countries, the Gazelle has served in combat\ - \ operations across the world including the 1991 Gulf War, 1982 Lebanon War, Syria,\ - \ and other conflicts.\n\nThe Gazelle is powered by a single turbine engine that\ - \ is connected to three glass-fiber reinforced plastic main rotor blades with a\ - \ bearingless main rotor developed by B\xF6lkow GmbH. It is also the first helicopter\ - \ which features the famous Fenestron tail rotor." -introduced: 1977 -lha_capable: true -cabin_size: 2 -can_carry_crates: false -manufacturer: "A\xE9rospatiale" -origin: France -price: 8 -role: Light Attack -variants: - SA 342M Gazelle Mistral: {} -kneeboard_units: "metric" -tasks: {} -hit_points: 18 diff --git a/resources/units/aircraft/SH-60B.yaml b/resources/units/aircraft/SH-60B.yaml deleted file mode 100644 index 5ae3f7532..000000000 --- a/resources/units/aircraft/SH-60B.yaml +++ /dev/null @@ -1,29 +0,0 @@ -class: Helicopter -cabin_size: 6 -can_carry_crates: true -carrier_capable: true -description: - The Sikorsky SH-60/MH-60 Seahawk (or Sea Hawk) is a twin turboshaft engine, - multi-mission United States Navy helicopter based on the United States Army UH-60 - Black Hawk and a member of the Sikorsky S-70 family. The most significant modifications - are the folding main rotor and a hinged tail to reduce its footprint aboard ships. - The U.S. Navy uses the H-60 airframe under the model designations SH-60B, SH-60F, - HH-60H, MH-60R, and MH-60S. Able to deploy aboard any air-capable frigate, destroyer, - cruiser, fast combat support ship, amphibious assault ship, Littoral combat ship - or aircraft carrier, the Seahawk can handle anti-submarine warfare (ASW), anti-surface - warfare (ASUW), naval special warfare (NSW) insertion, search and rescue (SAR), - combat search and rescue (CSAR), vertical replenishment (VERTREP), and medical evacuation - (MEDEVAC). -introduced: 1984 -lha_capable: true -manufacturer: Sikorsky -origin: USA -price: 6 -role: Transport/Anti-Ship -variants: - SH-60B Seahawk: {} -tasks: - Air Assault: 70 - Anti-ship: 0 - Transport: 50 -hit_points: 14 diff --git a/resources/units/aircraft/SpitfireLFMkIX.yaml b/resources/units/aircraft/SpitfireLFMkIX.yaml deleted file mode 100644 index 8592110e5..000000000 --- a/resources/units/aircraft/SpitfireLFMkIX.yaml +++ /dev/null @@ -1,58 +0,0 @@ -always_keeps_gun: true -description: - 'The British Spitfire is one of the most iconic fighter aircraft of World - War II. Most famous for its role in the Battle of Britain, the Spitfire served as - Britain''s primary fighter during the entirety of the war. The Spitfire combines - graceful lines, eye-watering dogfight performance, and heavy firepower in its later - variants. - - - The Spitfire Mk IX was originally developed as a stopgap measure as a response to - the appearance of the Focke-Wulf FW 190A. - - - The Spitfire IX is powered by the Merlin 66. This engine produces its best performance - at slightly lower altitudes than the older Merlin 61. Spitfires equipped with this - engine were designated LF Mk IX. This was the most numerous version of the Mk IX, - with 4,010 produced. The majority of Mk IXs of all types used the standard "c" wing, - which would often carry two 20mm cannon and four .303in machine guns. - - - The Mk IX was a significant improvement on the Mk V. It had a top speed of 409 mph - at 28,000 feet, an increase of 40 miles per hour. Its service ceiling rose from - 36,200 feet to 43,000 feet. It could climb at 4,000 feet per minute. In July 1942, - an early Mk IX was flown against a captured Fw 190A, and the two aircraft were discovered - to have very similar capabilities. The RAF had its answer to the Fw 190 problem. - - - The Mk IX replaced the Mk V from June 1942. It allowed the RAF to go back onto the - offensive in occupied Europe, and resume the "circus", "ramrod" and "rodeo" raids. - Its first combat success came on 30 July 1942, when a Spitfire Mk IX shot down a - Fw 190. Amongst other notable achievements, the Mk IX took part in the highest altitude - combat of the Second World War, when it intercepted a Ju 86R at 43,000 feet over - Southampton on 12 September 1942. On 5 October 1944 Spitfire Mk IXs of 401 Squadron - were the first allied aircraft to shoot down an Me 262 Jet. The Mk IX remained in - service until the end of the war, even after the appearance of the Griffon powered - Mk XIV.' -introduced: 1943 -manufacturer: Supermarine -origin: UK -price: 3 -role: Fighter -gunfighter: true -variants: - Spitfire LF Mk IX: {} -kneeboard_units: "imperial" -tasks: - BAI: 80 - BARCAP: 80 - CAS: 80 - DEAD: 40 - Escort: 80 - Fighter sweep: 80 - Intercept: 80 - OCA/Aircraft: 80 - OCA/Runway: 40 - Strike: 40 - TARCAP: 80 -hit_points: 18 diff --git a/resources/units/aircraft/SpitfireLFMkIXCW.yaml b/resources/units/aircraft/SpitfireLFMkIXCW.yaml deleted file mode 100644 index b7f940823..000000000 --- a/resources/units/aircraft/SpitfireLFMkIXCW.yaml +++ /dev/null @@ -1,58 +0,0 @@ -always_keeps_gun: true -description: - 'The British Spitfire is one of the most iconic fighter aircraft of World - War II. Most famous for its role in the Battle of Britain, the Spitfire served as - Britain''s primary fighter during the entirety of the war. The Spitfire combines - graceful lines, eye-watering dogfight performance, and heavy firepower in its later - variants. - - - The Spitfire Mk IX was originally developed as a stopgap measure as a response to - the appearance of the Focke-Wulf FW 190A. - - - The Spitfire IX is powered by the Merlin 66. This engine produces its best performance - at slightly lower altitudes than the older Merlin 61. Spitfires equipped with this - engine were designated LF Mk IX. This was the most numerous version of the Mk IX, - with 4,010 produced. The majority of Mk IXs of all types used the standard "c" wing, - which would often carry two 20mm cannon and four .303in machine guns. - - - The Mk IX was a significant improvement on the Mk V. It had a top speed of 409 mph - at 28,000 feet, an increase of 40 miles per hour. Its service ceiling rose from - 36,200 feet to 43,000 feet. It could climb at 4,000 feet per minute. In July 1942, - an early Mk IX was flown against a captured Fw 190A, and the two aircraft were discovered - to have very similar capabilities. The RAF had its answer to the Fw 190 problem. - - - The Mk IX replaced the Mk V from June 1942. It allowed the RAF to go back onto the - offensive in occupied Europe, and resume the "circus", "ramrod" and "rodeo" raids. - Its first combat success came on 30 July 1942, when a Spitfire Mk IX shot down a - Fw 190. Amongst other notable achievements, the Mk IX took part in the highest altitude - combat of the Second World War, when it intercepted a Ju 86R at 43,000 feet over - Southampton on 12 September 1942. On 5 October 1944 Spitfire Mk IXs of 401 Squadron - were the first allied aircraft to shoot down an Me 262 Jet. The Mk IX remained in - service until the end of the war, even after the appearance of the Griffon powered - Mk XIV.' -introduced: 1943 -manufacturer: Supermarine -origin: UK -price: 3 -role: Fighter -gunfighter: true -variants: - Spitfire LF Mk IX (Clipped Wings): {} -kneeboard_units: "imperial" -tasks: - BAI: 90 - BARCAP: 90 - CAS: 90 - DEAD: 50 - Escort: 90 - Fighter sweep: 90 - Intercept: 90 - OCA/Aircraft: 90 - OCA/Runway: 50 - Strike: 50 - TARCAP: 90 -hit_points: 18 diff --git a/resources/units/aircraft/Su-17M4.yaml b/resources/units/aircraft/Su-17M4.yaml deleted file mode 100644 index 3f4880269..000000000 --- a/resources/units/aircraft/Su-17M4.yaml +++ /dev/null @@ -1,30 +0,0 @@ -description: - The Sukhoi Su-17 (izdeliye S-32) is a variable-sweep wing fighter-bomber - developed for the Soviet military. Its NATO reporting name is "Fitter". Developed - from the Sukhoi Su-7, the Su-17 was the first variable-sweep wing aircraft to enter - Soviet service. Two subsequent Sukhoi aircraft, the Su-20 and Su-22, have usually - been regarded as variants of the Su-17. The Su-17 has had a long career and has - been operated by many other air forces of including the Russian Federation, other - former Soviet republics, the former Warsaw Pact, countries in the Arab world, Angola - and Peru. -introduced: 1981 -manufacturer: Sukhoi -origin: USSR/Russia -price: 10 -role: Fighter-Bomber -max_range: 300 -variants: - Su-17M4 Fitter-K: {} - Su-22M4 Fitter-K: - introduced: 1983 -tasks: - Anti-ship: 120 - BAI: 600 - CAS: 600 - DEAD: 320 - OCA/Aircraft: 600 - OCA/Runway: 520 - SEAD: 40 - SEAD Escort: 40 - Strike: 520 -hit_points: 20 diff --git a/resources/units/aircraft/Su-24M.yaml b/resources/units/aircraft/Su-24M.yaml deleted file mode 100644 index bb7ae1e7a..000000000 --- a/resources/units/aircraft/Su-24M.yaml +++ /dev/null @@ -1,29 +0,0 @@ -description: - "The Sukhoi Su-24 (NATO reporting name: Fencer) is a supersonic, all-weather - attack aircraft developed in the Soviet Union. The aircraft has a variable-sweep - wing, twin-engines and a side-by-side seating arrangement for its crew of two. It - was the first of the USSR's aircraft to carry an integrated digital navigation/attack - system. It remains in service with the Russian Air Force, Syrian Air Force, Ukrainian - Air Force, Azerbaijan Air Force , Iraqi Air Force and various air forces to which - it was exported." -introduced: 1983 -manufacturer: Sukhoi -origin: USSR/Russia -price: 14 -role: Attack -max_range: 200 -variants: - Su-24M Fencer-D: {} - Su-24MK Fencer-D: - introduced: 1988 -tasks: - Anti-ship: 130 - BAI: 610 - CAS: 610 - DEAD: 330 - OCA/Aircraft: 610 - OCA/Runway: 510 - SEAD: 50 - SEAD Escort: 50 - Strike: 510 -hit_points: 20 diff --git a/resources/units/aircraft/Su-24MR.yaml b/resources/units/aircraft/Su-24MR.yaml deleted file mode 100644 index f1b38271e..000000000 --- a/resources/units/aircraft/Su-24MR.yaml +++ /dev/null @@ -1,6 +0,0 @@ -price: 15 -max_range: 200 -variants: - Su-24MR: null -tasks: {} -hit_points: 20 diff --git a/resources/units/aircraft/Su-25.yaml b/resources/units/aircraft/Su-25.yaml deleted file mode 100644 index f171add64..000000000 --- a/resources/units/aircraft/Su-25.yaml +++ /dev/null @@ -1,24 +0,0 @@ -always_keeps_gun: true -description: - The Su-25 'Grach' (Rook), NATO callsigned 'Frogfoot', is a dedicated - strike attack aircraft designed for the close air support and anti-tank roles. The - Su-25 has seen combat in several conflicts during its more than 30 years in service. - The Su-25 combines excellent pilot protection and high speed compared to most dedicated - attack aircraft. It can be armed with a variety of weapon systems including guided - missiles, bombs, rockets, and its internal 30mm cannon. -introduced: 1981 -manufacturer: Sukhoi -origin: USSR/Russia -price: 11 -role: Close Air Support/Attack -max_range: 200 -variants: - Su-25 Frogfoot: {} -kneeboard_units: "metric" -tasks: - BAI: 770 - CAS: 770 - OCA/Aircraft: 770 - OCA/Runway: 480 - Strike: 480 -hit_points: 32 diff --git a/resources/units/aircraft/Su-25T.yaml b/resources/units/aircraft/Su-25T.yaml deleted file mode 100644 index 9d6851d07..000000000 --- a/resources/units/aircraft/Su-25T.yaml +++ /dev/null @@ -1,27 +0,0 @@ -always_keeps_gun: true -description: - The Su-25 'Grach' (Rook), NATO callsigned 'Frogfoot', is a dedicated - strike attack aircraft designed for the close air support and anti-tank roles. The - Su-25 has seen combat in several conflicts during its more than 30 years in service. - The Su-25 combines excellent pilot protection and high speed compared to most dedicated - attack aircraft. It can be armed with a variety of weapon systems including guided - missiles, bombs, rockets, and its internal 30mm cannon. -introduced: 1990 -manufacturer: Sukhoi -origin: USSR/Russia -price: 18 -role: Close Air Support/Attack -max_range: 200 -variants: - Su-25T Frogfoot: {} -kneeboard_units: "metric" -tasks: - BAI: 780 - CAS: 780 - DEAD: 420 - OCA/Aircraft: 780 - OCA/Runway: 490 - SEAD: 140 - SEAD Escort: 140 - Strike: 490 -hit_points: 32 diff --git a/resources/units/aircraft/Su-27.yaml b/resources/units/aircraft/Su-27.yaml deleted file mode 100644 index 073bcadb0..000000000 --- a/resources/units/aircraft/Su-27.yaml +++ /dev/null @@ -1,29 +0,0 @@ -description: - The Su-27, NATO codename Flanker, is one of the pillars of modern-day - Russian combat aviation. Built to counter the American F-15 Eagle, the Flanker is - a twin-engine, supersonic, highly manoeuvrable air superiority fighter. The Flanker - is equally capable of engaging targets well beyond visual range as it is in a dogfight - given its amazing slow speed and high angle attack manoeuvrability. Using its radar - and stealthy infrared search and track system, the Flanker can employ a wide array - of radar and infrared guided missiles. The Flanker also includes a helmet-mounted - sight that allows you to simply look at a target to lock it up! In addition to its - powerful air-to-air capabilities, the Flanker can also be armed with bombs and unguided - rockets to fulfil a secondary ground attack role. -introduced: 1985 -manufacturer: Sukhoi -origin: USSR/Russia -price: 18 -role: Air-Superiority Fighter -max_range: 300 -variants: - Su-27 Flanker-B: {} -kneeboard_units: "metric" -tasks: - BARCAP: 480 - Escort: 480 - Fighter sweep: 480 - Intercept: 480 - OCA/Runway: 440 - Strike: 440 - TARCAP: 480 -hit_points: 20 diff --git a/resources/units/aircraft/Su-30.yaml b/resources/units/aircraft/Su-30.yaml deleted file mode 100644 index f0ef0c4ae..000000000 --- a/resources/units/aircraft/Su-30.yaml +++ /dev/null @@ -1,35 +0,0 @@ -description: - "The Sukhoi Su-30 (Russian: \u0421\u0443\u0445\u043E\u0439 \u0421\u0443\ - -30; NATO reporting name: Flanker-C/G/H) is a twin-engine, two-seat supermaneuverable\ - \ fighter aircraft developed in the Soviet Union by Russia's Sukhoi Aviation Corporation.\ - \ It is a multirole fighter for all-weather, air-to-air and air-to-surface deep\ - \ interdiction missions. 630 numbers have been build." -introduced: 1996 -manufacturer: Sukhoi -origin: USSR/Russia -price: 23 -role: Multirole Fighter -max_range: 300 -variants: - Su-30 Flanker-C: {} - Su-30MKK Flanker-G: - introduced: 2000 - manufacturer: Sukhoi - origin: USSR/Russia - role: Multirole Fighter -tasks: - Anti-ship: 90 - BAI: 560 - BARCAP: 490 - CAS: 560 - DEAD: 300 - Escort: 490 - Fighter sweep: 490 - Intercept: 490 - OCA/Aircraft: 560 - OCA/Runway: 450 - SEAD: 20 - SEAD Escort: 20 - Strike: 450 - TARCAP: 490 -hit_points: 20 diff --git a/resources/units/aircraft/Su-33.yaml b/resources/units/aircraft/Su-33.yaml deleted file mode 100644 index f6147b909..000000000 --- a/resources/units/aircraft/Su-33.yaml +++ /dev/null @@ -1,44 +0,0 @@ -carrier_capable: true -description: - 'The Su-33 has been the backbone of Russian aircraft carrier aviation - since the late 1990s and is an all-weather fighter capable of engaging both air - and surface targets. Based on the powerful Su-27 "Flanker", the Su-33 is a navalized - version suited for operations aboard the Admiral Kuznetsov aircraft carrier. Changes - to the Su-33 include strengthened landing gear, folding wings, more powerful engines, - and the very visible canards. - - - The Su-33 is equipped with a powerful pulse doppler radar and an Infrared Search - and Track (IRST) for engaging aerial targets with a wide range of radar- and infrared-guided - missiles and its internal cannon. For air-to-surface attack, the Su-33 can be armed - with many types of unguided bombs, rockets, and cluster munitions. - - - Despite its large size, the Su-33 is very capable in a dogfight when combined with - its integral helmet-mounted sight and off-boresight missiles.' -introduced: 1998 -manufacturer: Sukhoi -origin: USSR/Russia -price: 22 -role: Carrier-based Multirole Fighter -max_range: 300 -variants: - J-15 Flanker X-2: - introduced: 2013 - manufacturer: Shenyang - origin: China - role: Carrier-based Multirole Fighter - Su-33 Flanker-D: {} -kneeboard_units: "metric" -tasks: - BAI: 590 - BARCAP: 510 - CAS: 590 - Escort: 510 - Fighter sweep: 510 - Intercept: 510 - OCA/Aircraft: 590 - OCA/Runway: 460 - Strike: 460 - TARCAP: 510 -hit_points: 20 diff --git a/resources/units/aircraft/Su-34.yaml b/resources/units/aircraft/Su-34.yaml deleted file mode 100644 index 98f91c91a..000000000 --- a/resources/units/aircraft/Su-34.yaml +++ /dev/null @@ -1,33 +0,0 @@ -description: - "The Sukhoi Su-34 (Russian: \u0421\u0443\u0445\u043E\u0439 \u0421\u0443\ - -34; NATO reporting name: Fullback) is a Soviet-origin Russian twin-engine, twin-seat,\ - \ all-weather supersonic medium-range fighter-bomber/strike aircraft. It first flew\ - \ in 1990, intended for the Soviet Air Forces, and it entered service in 2014 with\ - \ the Russian Air Force. Based on the Sukhoi Su-27 Flanker air superiority fighter,\ - \ the Su-34 has an armored cockpit for side-by-side seating of its two-person crew.\ - \ The Su-34 is designed primarily for tactical deployment against ground and naval\ - \ targets (tactical bombing/attack/interdiction roles, including against small and\ - \ mobile targets) on solo and group missions in daytime and at night, under favourable\ - \ and adverse weather conditions and in a hostile environment with counter-fire\ - \ and electronic Warfare (EW) counter-measures deployed, as well as for aerial reconnaissance.\ - \ The Su-34 will eventually replace the Su-24 tactical strike fighter and the Tu-22M3\ - \ long-distance bomber." -introduced: 2014 -manufacturer: Sukhoi -origin: USSR/Russia -price: 26 -role: Fighter-Bomber/Strike Fighter -max_range: 300 -variants: - Su-34 Fullback: {} -tasks: - Anti-ship: 100 - BAI: 800 - CAS: 800 - DEAD: 310 - OCA/Aircraft: 800 - OCA/Runway: 470 - SEAD: 30 - SEAD Escort: 30 - Strike: 470 -hit_points: 24 diff --git a/resources/units/aircraft/Su-57.yaml b/resources/units/aircraft/Su-57.yaml deleted file mode 100644 index 0e86059f5..000000000 --- a/resources/units/aircraft/Su-57.yaml +++ /dev/null @@ -1,21 +0,0 @@ -description: - "The Sukhoi Su-57 (Russian: \u0421\u0443\u0445\u043E\u0439 \u0421\u0443\ - -57; NATO reporting name: Felon) is a single-seat, twin-engine stealth multirole\ - \ fighter developed by Sukhoi for the Russian Aerospace Forces. According to Sukhoi,\ - \ the multirole fighter is designed to have supercruise, supermaneuverability, stealth,\ - \ and integrated avionics to overcome the previous generations fighter aircraft\ - \ as well as ground and naval defences. The Su-57 is intended to succeed the MiG-29\ - \ and Su-27 in the Russian Air Force and entered service in December 2020." -introduced: 2020 -manufacturer: Sukhoi -origin: Russia -price: 40 -role: Stealth Air-Superiority Fighter -variants: - Su-57 Felon: {} -tasks: - BARCAP: 560 - Escort: 560 - Fighter sweep: 560 - Intercept: 560 - TARCAP: 560 diff --git a/resources/units/aircraft/Tornado GR4.yaml b/resources/units/aircraft/Tornado GR4.yaml deleted file mode 100644 index 83e773aa1..000000000 --- a/resources/units/aircraft/Tornado GR4.yaml +++ /dev/null @@ -1,24 +0,0 @@ -description: - "The Panavia Tornado is a family of twin-engine, variable-sweep wing - multirole combat aircraft, jointly developed and manufactured by Italy, the United - Kingdom and West Germany. There are three primary Tornado variants: the Tornado - IDS (interdictor/strike) fighter-bomber, the suppression of enemy air defences Tornado - ECR (electronic combat/reconnaissance) and the Tornado ADV (air defence variant) - interceptor aircraft." -introduced: 1996 -manufacturer: Panavia -origin: UK/Italy/West Germany -price: 17 -role: Strike Fighter -variants: - Tornado GR4: {} -tasks: - Anti-ship: 70 - BAI: 730 - CAS: 730 - DEAD: 280 - OCA/Aircraft: 730 - SEAD: 0 - SEAD Escort: 0 - Strike: 620 -hit_points: 20 diff --git a/resources/units/aircraft/Tornado IDS.yaml b/resources/units/aircraft/Tornado IDS.yaml deleted file mode 100644 index d10e82f99..000000000 --- a/resources/units/aircraft/Tornado IDS.yaml +++ /dev/null @@ -1,25 +0,0 @@ -description: - "The Panavia Tornado is a family of twin-engine, variable-sweep wing - multirole combat aircraft, jointly developed and manufactured by Italy, the United - Kingdom and West Germany. There are three primary Tornado variants: the Tornado - IDS (interdictor/strike) fighter-bomber, the suppression of enemy air defences Tornado - ECR (electronic combat/reconnaissance) and the Tornado ADV (air defence variant) - interceptor aircraft." -introduced: 1979 -manufacturer: Panavia -origin: UK/Italy/West Germany -price: 17 -role: Strike Fighter -variants: - Tornado IDS: {} -tasks: - Anti-ship: 80 - BAI: 720 - CAS: 720 - DEAD: 430 - OCA/Aircraft: 720 - OCA/Runway: 530 - SEAD: 150 - SEAD Escort: 150 - Strike: 530 -hit_points: 20 diff --git a/resources/units/aircraft/Tu-142.yaml b/resources/units/aircraft/Tu-142.yaml deleted file mode 100644 index ee5bf8924..000000000 --- a/resources/units/aircraft/Tu-142.yaml +++ /dev/null @@ -1,20 +0,0 @@ -description: - "The Tupolev Tu-142 (Russian: \u0422\u0443\u043F\u043E\u043B\u0435\u0432\ - \ \u0422\u0443-142; NATO reporting name: Bear F/J) is a Soviet/Russian maritime\ - \ reconnaissance and anti-submarine warfare (ASW) aircraft derived from the Tu-95\ - \ turboprop strategic bomber. A specialised communications variant designated Tu-142MR\ - \ was tasked with long-range communications duties with Soviet ballistic missile\ - \ submarines. The Tu-142 was designed by the Tupolev design bureau, and manufactured\ - \ by the Kuibyshev Aviation and Taganrog Machinery Plants from 1968 to 1994. Formerly\ - \ operated by the Soviet Navy and Ukrainian Air Force, the Tu-142 currently serves\ - \ with the Russian Navy." -introduced: 1972 -manufacturer: Tupolev -origin: USSR/Russia -price: 35 -role: Maritime Patrol/Anti-Ship -variants: - Tu-142 Bear-F: {} -tasks: - Anti-ship: 180 -hit_points: 60 diff --git a/resources/units/aircraft/Tu-160.yaml b/resources/units/aircraft/Tu-160.yaml deleted file mode 100644 index ee79a2101..000000000 --- a/resources/units/aircraft/Tu-160.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: - "The Tupolev Tu-160 (Russian: \u0422\u0443\u043F\u043E\u043B\u0435\u0432\ - \ \u0422\u0443-160 \u0411\u0435\u043B\u044B\u0439 \u043B\u0435\u0431\u0435\u0434\ - \u044C, romanized: Belyj Lebe\u010F, lit.\u2009'White Swan'; NATO reporting name:\ - \ Blackjack) is a supersonic, variable-sweep wing heavy strategic bomber designed\ - \ by the Tupolev Design Bureau in the Soviet Union in the 1970s. It is the largest\ - \ and heaviest Mach 2+ supersonic military aircraft ever built and next to the experimental\ - \ XB-70 Valkyrie in overall length. As of 2021, it is the largest and heaviest combat\ - \ aircraft, the fastest bomber in use and the largest and heaviest variable-sweep\ - \ wing airplane ever flown." -introduced: 1987 -manufacturer: Tupolev -origin: USSR/Russia -price: 45 -role: Supersonic Strategic Bomber -max_range: 2000 -variants: - Tu-160 Blackjack: {} -tasks: - DEAD: 200 - Strike: 680 -hit_points: 60 diff --git a/resources/units/aircraft/Tu-22M3.yaml b/resources/units/aircraft/Tu-22M3.yaml deleted file mode 100644 index 6fff9db62..000000000 --- a/resources/units/aircraft/Tu-22M3.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: - "The Tupolev Tu-22M (Russian: \u0422\u0443\u043F\u043E\u043B\u0435\u0432\ - \ \u0422\u0443-22\u041C; NATO reporting name: Backfire) is a supersonic, variable-sweep\ - \ wing, long-range strategic and maritime strike bomber developed by the Tupolev\ - \ Design Bureau in the 1960s. According to some sources, the bomber was believed\ - \ to be designated Tu-26 at one time. During the Cold War, the Tu-22M was operated\ - \ by the Soviet Air Forces (VVS) in a missile carrier strategic bombing role, and\ - \ by the Soviet Naval Aviation (Aviacija Vojenno-Morskogo Flota, AVMF) in a long-range\ - \ maritime anti-shipping role. Significant numbers remain in service with the Russian\ - \ Air Force, and as of 2014 more than 100 Tu-22Ms are in use." -introduced: 1983 -manufacturer: Tupolev -origin: USSR/Russia -price: 40 -role: Strategic/Maritime Strike Bomber -variants: - Tu-22M3 Backfire-C: {} -tasks: - Anti-ship: 170 - OCA/Runway: 650 - Strike: 660 -hit_points: 45 diff --git a/resources/units/aircraft/Tu-95MS.yaml b/resources/units/aircraft/Tu-95MS.yaml deleted file mode 100644 index e1bcbcdd1..000000000 --- a/resources/units/aircraft/Tu-95MS.yaml +++ /dev/null @@ -1,22 +0,0 @@ -description: - "The Tupolev Tu-95 (Russian: \u0422\u0443\u043F\u043E\u043B\u0435\u0432\ - \ \u0422\u0443-95; NATO reporting name: \"Bear\") is a large, four-engine turboprop-powered\ - \ strategic bomber and missile platform. First flown in 1952, the Tu-95 entered\ - \ service with the Long-Range Aviation of the Soviet Air Forces in 1956 and is expected\ - \ to serve the Russian Aerospace Forces until at least 2040. A development of the\ - \ bomber for maritime patrol is designated Tu-142, while a passenger airliner derivative\ - \ was called Tu-114. The aircraft has four Kuznetsov NK-12 engines with contra-rotating\ - \ propellers. It is the only propeller-powered strategic bomber still in operational\ - \ use today. The Tu-95 is one of the loudest military aircraft, particularly because\ - \ the tips of the propeller blades move faster than the speed of sound" -introduced: 1981 -manufacturer: Tupolev -origin: USSR/Russia -price: 35 -role: Strategic Bomber -variants: - Tu-95MS Bear-H: {} -tasks: - DEAD: 190 - Strike: 670 -hit_points: 60 diff --git a/resources/units/aircraft/UH-1H.yaml b/resources/units/aircraft/UH-1H.yaml deleted file mode 100644 index febb65f1f..000000000 --- a/resources/units/aircraft/UH-1H.yaml +++ /dev/null @@ -1,35 +0,0 @@ -class: Helicopter -carrier_capable: true -description: - The UH-1 Iroquois, better known as the Huey, is one of the most iconic - helicopters in the world. Indispensable in the Vietnam War, the Huey continues to - serve in both military and civilian roles around the globe today. -introduced: 1967 -lha_capable: true -cabin_size: 6 -can_carry_crates: true -manufacturer: Bell -origin: USA -price: 4 -role: Transport/Light Attack -variants: - UH-1D Iroquois: {} - UH-1H Iroquois: {} -radios: - # Ideally this would use the AN/ARC-131 because that radio is supposed - # to be used for flight comms, but DCS won't allow it as the flight's - # frequency, nor will it allow the AN/ARC-134. - intra_flight: AN/ARC-51BX - inter_flight: AN/ARC-51BX - channels: - type: common - namer: huey - intra_flight_radio_index: 1 - inter_flight_radio_index: 1 -tasks: - Air Assault: 50 - BAI: 210 - CAS: 210 - OCA/Aircraft: 210 - Transport: 30 -hit_points: 12 diff --git a/resources/units/aircraft/UH-60A.yaml b/resources/units/aircraft/UH-60A.yaml deleted file mode 100644 index 2d90da0d9..000000000 --- a/resources/units/aircraft/UH-60A.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Helicopter -carrier_capable: true -lha_capable: true -price: 4 -cabin_size: 10 -can_carry_crates: true -variants: - UH-60A: null -tasks: - Air Assault: 60 - Transport: 40 -hit_points: 14 diff --git a/resources/units/aircraft/UH-60L.yaml b/resources/units/aircraft/UH-60L.yaml deleted file mode 100644 index 7e876ccf8..000000000 --- a/resources/units/aircraft/UH-60L.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Helicopter -description: - The Sikorsky UH-60 Black Hawk is a four-blade, twin-engine, medium-lift utility helicopter manufactured by Sikorsky Aircraft. - The UH-60A entered service with the U.S. Army in 1979, to replace the Bell UH-1 Iroquois as the Army's tactical transport helicopter. - The UH-60L is an improved utility variant. -introduced: 1989 -carrier_capable: true -lha_capable: true -cabin_size: 10 -can_carry_crates: true -manufacturer: Sikorsky -origin: USA -price: 4 -role: Transport -variants: - UH-60L: {} -tasks: - Air Assault: 80 - Transport: 60 diff --git a/resources/units/aircraft/VSN_F104G.yaml b/resources/units/aircraft/VSN_F104G.yaml deleted file mode 100644 index 9bbd516a7..000000000 --- a/resources/units/aircraft/VSN_F104G.yaml +++ /dev/null @@ -1,30 +0,0 @@ -description: - "The Lockheed F-104 Starfighter is a single-engine, supersonic interceptor aircraft\ - \ which was extensively deployed as a fighter-bomber during the Cold War. Created \ - \ as a day fighter by Lockheed as one of the Century Series of fighter aircraft \ - \ for the United States Air Force (USAF), it was developed into an all-weather \ - \ multirole aircraft in the early 1960s and produced by several other nations, \ - \ seeing widespread service outside the United States. \ - \ The F-104G variant was used by West German Luftwaffe and Bundesmarine \ - \ as well as other NATO countries." -introduced: 1958 -manufacturer: Lockheed -origin: USA -price: 9 -role: Fighter-Bomber -max_range: 100 -gunfighter: true -variants: - F-104G Starfighter: {} -tasks: - BAI: 190 - BARCAP: 180 - CAS: 190 - DEAD: 120 - Escort: 180 - Fighter sweep: 180 - Intercept: 180 - OCA/Aircraft: 190 - OCA/Runway: 110 - Strike: 110 - TARCAP: 180 diff --git a/resources/units/aircraft/VSN_F104S.yaml b/resources/units/aircraft/VSN_F104S.yaml deleted file mode 100644 index 7bc72a77e..000000000 --- a/resources/units/aircraft/VSN_F104S.yaml +++ /dev/null @@ -1,23 +0,0 @@ -description: - "The Lockheed F-104 Starfighter is a single-engine, supersonic interceptor aircraft\ - \ which was extensively deployed as a fighter-bomber during the Cold War. Created \ - \ as a day fighter by Lockheed as one of the Century Series of fighter aircraft \ - \ for the United States Air Force (USAF), it was developed into an all-weather \ - \ multirole aircraft in the early 1960s and produced by several other nations, \ - \ seeing widespread service outside the United States. \ - \ The Aeritalia F-104S is a licensed production Italian version." -introduced: 1966 -manufacturer: Lockheed -origin: USA -price: 9 -role: Light Fighter -max_range: 100 -gunfighter: true -variants: - F-104S Starfighter: {} -tasks: - BARCAP: 190 - Escort: 190 - Fighter sweep: 190 - Intercept: 190 - TARCAP: 190 diff --git a/resources/units/aircraft/VSN_F104S_AG.yaml b/resources/units/aircraft/VSN_F104S_AG.yaml deleted file mode 100644 index 9c972fa51..000000000 --- a/resources/units/aircraft/VSN_F104S_AG.yaml +++ /dev/null @@ -1,24 +0,0 @@ -description: - "The Lockheed F-104 Starfighter is a single-engine, supersonic interceptor aircraft\ - \ which was extensively deployed as a fighter-bomber during the Cold War. Created \ - \ as a day fighter by Lockheed as one of the Century Series of fighter aircraft \ - \ for the United States Air Force (USAF), it was developed into an all-weather \ - \ multirole aircraft in the early 1960s and produced by several other nations, \ - \ seeing widespread service outside the United States. \ - \ The Aeritalia F-104S is a licensed production Italian version." -introduced: 1966 -manufacturer: Lockheed -origin: USA -price: 9 -role: Fighter-Bomber -max_range: 100 -gunfighter: true -variants: - F-104S Starfighter A/G: {} -tasks: - BAI: 200 - CAS: 200 - DEAD: 130 - OCA/Aircraft: 200 - OCA/Runway: 120 - Strike: 120 diff --git a/resources/units/aircraft/VSN_F4B.yaml b/resources/units/aircraft/VSN_F4B.yaml deleted file mode 100644 index d648378ea..000000000 --- a/resources/units/aircraft/VSN_F4B.yaml +++ /dev/null @@ -1,31 +0,0 @@ -carrier_capable: true -description: - Proving highly adaptable, the F-4 entered service with the Navy in 1961 - before it was adopted by the United States Marine Corps and the United States Air - Force, and by the mid-1960s it had become a major part of their air arms. Phantom - production ran from 1958 to 1981 with a total of 5,195 aircraft built, making it - the most produced American supersonic military aircraft in history, and cementing - its position as an iconic combat aircraft of the Cold War. The F-4 was used extensively - during the Vietnam War. It served as the principal air superiority fighter for the - U.S. Air Force, Navy, and Marine Corps and became important in the ground-attack - and aerial reconnaissance roles late in the war. The F-4B is an early US Navy variant. -introduced: 1961 -manufacturer: McDonnell Douglas -origin: USA -price: 9 -role: Fighter-Bomber -max_range: 200 -variants: - F-4B Phantom II: {} -tasks: - BAI: 180 - BARCAP: 220 - CAS: 180 - DEAD: 150 - Escort: 220 - Fighter sweep: 220 - Intercept: 220 - OCA/Aircraft: 180 - OCA/Runway: 350 - Strike: 350 - TARCAP: 220 diff --git a/resources/units/aircraft/VSN_F4C.yaml b/resources/units/aircraft/VSN_F4C.yaml deleted file mode 100644 index 79dcccc74..000000000 --- a/resources/units/aircraft/VSN_F4C.yaml +++ /dev/null @@ -1,32 +0,0 @@ -description: - Proving highly adaptable, the F-4 entered service with the Navy in 1961 - before it was adopted by the United States Marine Corps and the United States Air - Force, and by the mid-1960s it had become a major part of their air arms. Phantom - production ran from 1958 to 1981 with a total of 5,195 aircraft built, making it - the most produced American supersonic military aircraft in history, and cementing - its position as an iconic combat aircraft of the Cold War. The F-4 was used extensively - during the Vietnam War. It served as the principal air superiority fighter for the - U.S. Air Force, Navy, and Marine Corps and became important in the ground-attack - and aerial reconnaissance roles late in the war. The F-4C is an early USAF variant. -introduced: 1963 -manufacturer: McDonnell Douglas -origin: USA -price: 9 -role: Fighter-Bomber -max_range: 200 -variants: - F-4C Phantom II: {} -tasks: - BAI: 170 - BARCAP: 210 - CAS: 170 - DEAD: 140 - Escort: 210 - Fighter sweep: 210 - Intercept: 210 - OCA/Aircraft: 170 - OCA/Runway: 340 - SEAD: 60 - SEAD Escort: 60 - Strike: 340 - TARCAP: 210 diff --git a/resources/units/aircraft/WingLoong-I.yaml b/resources/units/aircraft/WingLoong-I.yaml deleted file mode 100644 index 266871a8d..000000000 --- a/resources/units/aircraft/WingLoong-I.yaml +++ /dev/null @@ -1,8 +0,0 @@ -price: 8 -variants: - WingLoong-I: null -tasks: - BAI: 20 - CAS: 20 - OCA/Aircraft: 20 -hit_points: 18 diff --git a/resources/units/aircraft/Yak-40.yaml b/resources/units/aircraft/Yak-40.yaml deleted file mode 100644 index b4c6462cb..000000000 --- a/resources/units/aircraft/Yak-40.yaml +++ /dev/null @@ -1,7 +0,0 @@ -price: 25 -max_range: 600 -variants: - Yak-40: null -tasks: - Transport: 100 -hit_points: 45 diff --git a/resources/units/ground_units/1L13 EWR.yaml b/resources/units/ground_units/1L13 EWR.yaml deleted file mode 100644 index 7ad298027..000000000 --- a/resources/units/ground_units/1L13 EWR.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 30 -variants: - EWR 1L13: null -hit_points: 2 diff --git a/resources/units/ground_units/2B11 mortar.yaml b/resources/units/ground_units/2B11 mortar.yaml deleted file mode 100644 index cf325caa1..000000000 --- a/resources/units/ground_units/2B11 mortar.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 1 -variants: - Mortar 2B11 120mm: null -hit_points: 1 diff --git a/resources/units/ground_units/2S6 Tunguska.yaml b/resources/units/ground_units/2S6 Tunguska.yaml deleted file mode 100644 index b205da503..000000000 --- a/resources/units/ground_units/2S6 Tunguska.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: SHORAD -description: "The 2K22 Tunguska (Russian: 2\u041A22 '\u0422\u0443\u043D\u0433\u0443\ - \u0441\u043A\u0430') is a Russian tracked self-propelled anti-aircraft weapon armed\ - \ with a surface-to-air gun and missile system. It is designed to provide day and\ - \ night protection for infantry and tank regiments against low-flying aircraft,\ - \ helicopters, and cruise missiles in all weather conditions. The NATO reporting\ - \ name for the missile used by the weapon system is SA-19 \"Grison\"." -introduced: 1982 -manufacturer: Ulyanovsk -origin: USSR/Russia -price: 30 -role: Self-Propelled Anti-Aircraft System -variants: - SA-19 Grison (2K22 Tunguska): {} -hit_points: 4 diff --git a/resources/units/ground_units/55G6 EWR.yaml b/resources/units/ground_units/55G6 EWR.yaml deleted file mode 100644 index 6daae557d..000000000 --- a/resources/units/ground_units/55G6 EWR.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 30 -variants: - EWR 55G6: null -hit_points: 2 diff --git a/resources/units/ground_units/5p73 V-601P ln.yaml b/resources/units/ground_units/5p73 V-601P ln.yaml deleted file mode 100644 index 9993ea430..000000000 --- a/resources/units/ground_units/5p73 V-601P ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 6 -variants: - SAM SA-3 (V-601P) LN 5P73: null diff --git a/resources/units/ground_units/5p73 s-125 ln.yaml b/resources/units/ground_units/5p73 s-125 ln.yaml deleted file mode 100644 index 241bb968e..000000000 --- a/resources/units/ground_units/5p73 s-125 ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 6 -variants: - SAM SA-3 S-125 "Goa" LN: null -hit_points: 2 diff --git a/resources/units/ground_units/AA20.yaml b/resources/units/ground_units/AA20.yaml deleted file mode 100644 index edc10e7aa..000000000 --- a/resources/units/ground_units/AA20.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SHORAD -price: 4 -variants: - 53T2: null diff --git a/resources/units/ground_units/AAV7.yaml b/resources/units/ground_units/AAV7.yaml deleted file mode 100644 index 0513ef0b6..000000000 --- a/resources/units/ground_units/AAV7.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: APC -description: "The Assault Amphibious Vehicle (AAV)\u2014official designation AAVP-7A1\ - \ (formerly known as Landing Vehicle, Tracked, Personnel-7 abbr. LVTP-7)\u2014is\ - \ a fully tracked amphibious landing vehicle manufactured by U.S. Combat Systems\ - \ (previously by United Defense, a former division of FMC Corporation). The AAV-P7/A1\ - \ is the current amphibious troop transport of the United States Marine Corps. It\ - \ is used by U.S. Marine Corps Assault Amphibian Battalions to land the surface\ - \ assault elements of the landing force and their equipment in a single lift from\ - \ assault shipping during amphibious operations to inland objectives and to conduct\ - \ mechanized operations and related combat support in subsequent mechanized operations\ - \ ashore. It is also operated by other forces." -introduced: 1971 -manufacturer: United Defense -origin: USA -price: 10 -role: Amphibious Armoured Personnel Carrier -variants: - AAVP-7A1 'Amtrac': {} -hit_points: 4 diff --git a/resources/units/ground_units/AMX-30B2.yaml b/resources/units/ground_units/AMX-30B2.yaml deleted file mode 100644 index df67a60ca..000000000 --- a/resources/units/ground_units/AMX-30B2.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Tank -description: 'The AMX-30 is a main battle tank designed by Ateliers de construction - d''Issy-les-Moulineaux (AMX, then GIAT) and first delivered to the French Army in - August 1965. ' -introduced: 1965 -manufacturer: GIAT Industries -origin: France -price: 18 -role: Main Battle Tank -variants: - AMX.30B2: {} diff --git a/resources/units/ground_units/AMX10RCR.yaml b/resources/units/ground_units/AMX10RCR.yaml deleted file mode 100644 index 793b530c6..000000000 --- a/resources/units/ground_units/AMX10RCR.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Recon -description: The AMX-10 RC is a reconnaissance vehicle built by GIAT. Over 240 are - in service in the French Army. In addition, 108 vehicles were sold to Morocco and - 12 to Qatar. RC stands for Roues-Canon, or wheeled gun. -introduced: 1970 -manufacturer: GIAT Industries -origin: France -price: 10 -role: Recon Vehicle -variants: - "AMX-10 RCR": {} diff --git a/resources/units/ground_units/AMX1375.yaml b/resources/units/ground_units/AMX1375.yaml deleted file mode 100644 index 9a821254a..000000000 --- a/resources/units/ground_units/AMX1375.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: Tank -description: "The AMX-13 is a French light tank produced from 1952 to 1987. It served with the French Army, as the Char 13t-75 Modèle 51, and was exported to more than 26 other nations. Named after its initial weight of 13 tonnes, and featuring a tough and reliable chassis,[1] it was fitted with an oscillating turret built by GIAT Industries (now Nexter) with revolver type magazines, which were also used on the Austrian SK-105 Kürassier.[1] Including prototypes and export versions, there are over a hundred variants including self-propelled guns, anti-aircraft systems, APCs, and ATGM versions. This specific version isan early one fitted with a 75mm gun." -introduced: 1952 -manufacturer: Atelier de Construction d'Issy-les-Moulineaux -origin: France -price: 10 -role: Light Tank -variants: - AMX-13 75mm: {} diff --git a/resources/units/ground_units/AMX1390.yaml b/resources/units/ground_units/AMX1390.yaml deleted file mode 100644 index dd17d2cd8..000000000 --- a/resources/units/ground_units/AMX1390.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: Tank -description: "The AMX-13 is a French light tank produced from 1952 to 1987. It served with the French Army, as the Char 13t-75 Modèle 51, and was exported to more than 26 other nations. Named after its initial weight of 13 tonnes, and featuring a tough and reliable chassis,[1] it was fitted with an oscillating turret built by GIAT Industries (now Nexter) with revolver type magazines, which were also used on the Austrian SK-105 Kürassier.[1] Including prototypes and export versions, there are over a hundred variants including self-propelled guns, anti-aircraft systems, APCs, and ATGM versions. This specific version is a late one fitted with a 90mm gun." -introduced: 1966 -manufacturer: Atelier de Construction d'Issy-les-Moulineaux -origin: France -price: 12 -role: Light Tank -variants: - AMX-13 90mm: {} diff --git a/resources/units/ground_units/BMD-1.yaml b/resources/units/ground_units/BMD-1.yaml deleted file mode 100644 index 6d05e4bb4..000000000 --- a/resources/units/ground_units/BMD-1.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: IFV -description: "The BMD-1 is a Soviet airborne amphibious tracked infantry fighting\ - \ vehicle, which was introduced in 1969 and first seen by the West in 1970. BMD\ - \ stands for Boyevaya Mashina Desanta (\u0411\u043E\u0435\u0432\u0430\u044F \u041C\ - \u0430\u0448\u0438\u043D\u0430 \u0414\u0435\u0441\u0430\u043D\u0442\u0430, which\ - \ literally translates to \"Combat Vehicle of the Airborne\"). It can be dropped\ - \ by parachute and although it resembles the BMP-1 it is in fact much smaller. The\ - \ BMD-1 was used as an IFV by the Soviet Army's airborne divisions." -introduced: 1969 -manufacturer: Volgograd -origin: USSR/Russia -price: 8 -role: Airborne Amphibious Infantry Fighting Vehicle -variants: - BMD-1: {} -hit_points: 3 diff --git a/resources/units/ground_units/BMP-1.yaml b/resources/units/ground_units/BMP-1.yaml deleted file mode 100644 index 750d5da90..000000000 --- a/resources/units/ground_units/BMP-1.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: IFV -description: "The BMD-1 is a Soviet airborne amphibious tracked infantry fighting\ - \ vehicle, which was introduced in 1969 and first seen by the West in 1970. BMD\ - \ stands for Boyevaya Mashina Desanta (\u0411\u043E\u0435\u0432\u0430\u044F \u041C\ - \u0430\u0448\u0438\u043D\u0430 \u0414\u0435\u0441\u0430\u043D\u0442\u0430, which\ - \ literally translates to \"Combat Vehicle of the Airborne\"). It can be dropped\ - \ by parachute and although it resembles the BMP-1 it is in fact much smaller. The\ - \ BMD-1 was used as an IFV by the Soviet Army's airborne divisions. " -introduced: 1966 -manufacturer: Kurganmashzavod -origin: USSR/Russia -price: 14 -role: Amphibious Infantry Fighting Vehicle -variants: - BMP-1: {} -hit_points: 5 diff --git a/resources/units/ground_units/BMP-2.yaml b/resources/units/ground_units/BMP-2.yaml deleted file mode 100644 index 89b0d764a..000000000 --- a/resources/units/ground_units/BMP-2.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: IFV -description: "The BMP-2 (Boyevaya Mashina Pekhoty, Russian: \u0411\u043E\u0435\u0432\ - \u0430\u044F \u041C\u0430\u0448\u0438\u043D\u0430 \u041F\u0435\u0445\u043E\u0442\ - \u044B, literally \"infantry combat vehicle\") is a second-generation, amphibious\ - \ infantry fighting vehicle introduced in the 1980s in the Soviet Union, following\ - \ on from the BMP-1 of the 1960s." -introduced: 1980 -manufacturer: Kurganmashzavod -origin: USSR/Russia -price: 16 -role: Amphibious Infantry Fighting Vehicle -variants: - BMP-2: {} -hit_points: 5 diff --git a/resources/units/ground_units/BMP-3.yaml b/resources/units/ground_units/BMP-3.yaml deleted file mode 100644 index e4963cc54..000000000 --- a/resources/units/ground_units/BMP-3.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: IFV -description: "The BMP-3 is a Soviet and Russian infantry fighting vehicle, successor\ - \ to the BMP-1 and BMP-2. The abbreviation BMP stands for boevaya mashina pehoty\ - \ (\u0431\u043E\u0435\u0432\u0430\u044F \u043C\u0430\u0448\u0438\u043D\u0430 \u043F\ - \u0435\u0445\u043E\u0442\u044B, literally \"infantry combat vehicle\")." -introduced: 1987 -manufacturer: Kurganmashzavod -origin: USSR/Russia -price: 18 -role: Amphibious Infantry Fighting Vehicle -variants: - BMP-3: {} -hit_points: 5 diff --git a/resources/units/ground_units/BRDM-2.yaml b/resources/units/ground_units/BRDM-2.yaml deleted file mode 100644 index 4d27dd7bf..000000000 --- a/resources/units/ground_units/BRDM-2.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: Recon -description: "The PT-76 is a Soviet amphibious light tank that was introduced in the\ - \ early 1950s and soon became the standard reconnaissance tank of the Soviet Army\ - \ and the other Warsaw Pact armed forces. It was widely exported to other friendly\ - \ states, like India, Iraq, Syria, North Korea and North Vietnam. Overall, some\ - \ 25 countries used the PT-76. The tank's full name is Floating Tank\u201376 (\u043F\ - \u043B\u0430\u0432\u0430\u044E\u0449\u0438\u0439 \u0442\u0430\u043D\u043A, plavayushchiy\ - \ tank, or \u041F\u0422-76). 76 stands for the caliber of the main armament: the\ - \ 76.2 mm D-56T series rifled tank gun." -introduced: 1962 -manufacturer: GAZ -origin: USSR/Russia -price: 6 -role: Amphibious Armoured Car -variants: - BRDM-2: {} -hit_points: 3 diff --git a/resources/units/ground_units/BTR-80.yaml b/resources/units/ground_units/BTR-80.yaml deleted file mode 100644 index f4a88c763..000000000 --- a/resources/units/ground_units/BTR-80.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: APC -description: "The BTR-80 (Russian: \u0431\u0440\u043E\u043D\u0435\u0442\u0440\u0430\ - \u043D\u0441\u043F\u043E\u0440\u0442\u0451\u0440, romanized: Bronyetransportyor,\ - \ literally \"Armoured Transporter\") is an 8\xD78 wheeled amphibious armoured personnel\ - \ carrier (APC) designed in the USSR. It was adopted in 1985 and replaced the previous\ - \ vehicles, the BTR-60 and BTR-70, in the Soviet Army. It was first deployed during\ - \ the Soviet\u2013Afghan War." -introduced: 1986 -manufacturer: Arzamas -origin: USSR/Russia -price: 8 -role: Amphibious Armoured Personnel Carrier -variants: - BTR-80: {} -hit_points: 3 diff --git a/resources/units/ground_units/BTR-82A.yaml b/resources/units/ground_units/BTR-82A.yaml deleted file mode 100644 index 7571ddbea..000000000 --- a/resources/units/ground_units/BTR-82A.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: APC -description: "The BTR-80 (Russian: \u0431\u0440\u043E\u043D\u0435\u0442\u0440\u0430\ - \u043D\u0441\u043F\u043E\u0440\u0442\u0451\u0440, romanized: Bronyetransportyor,\ - \ literally \"Armoured Transporter\") is an 8\xD78 wheeled amphibious armoured personnel\ - \ carrier (APC) designed in the USSR. It was adopted in 1985 and replaced the previous\ - \ vehicles, the BTR-60 and BTR-70, in the Soviet Army. It was first deployed during\ - \ the Soviet\u2013Afghan War. This is a modernized Version of the BTR 80." -introduced: 2013 -manufacturer: Arzamas -origin: Russia -price: 10 -role: Amphibious Armoured Personnel Carrier -variants: - BTR-82A: {} -hit_points: 3 diff --git a/resources/units/ground_units/BTR_D.yaml b/resources/units/ground_units/BTR_D.yaml deleted file mode 100644 index ed386431a..000000000 --- a/resources/units/ground_units/BTR_D.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: APC -description: "The BTR-D is a Soviet airborne multi-purpose tracked armoured personnel\ - \ carrier which was introduced in 1974 and first seen by the West in 1979 during\ - \ the Soviet\u2013Afghan War. BTR-D stands for Bronetransportyor Desanta (\u0411\ - \u0422\u0420-\u0414, \u0411\u0440\u043E\u043D\u0435\u0442\u0440\u0430\u043D\u0441\ - \u043F\u043E\u0440\u0442\u0435\u0440 \u0414\u0435\u0441\u0430\u043D\u0442\u0430\ - , literally \"armoured transporter of the Airborne\")" -introduced: 1974 -manufacturer: Volgograd -origin: USSR/Russia -price: 6 -role: Airborne Amphibious Armoured Personnel Carrier -variants: - BTR-D: {} -hit_points: 4 diff --git a/resources/units/ground_units/Bedford_MWD.yaml b/resources/units/ground_units/Bedford_MWD.yaml deleted file mode 100644 index 3de661b36..000000000 --- a/resources/units/ground_units/Bedford_MWD.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck Bedford: null -hit_points: 2 diff --git a/resources/units/ground_units/Blitz_36-6700A.yaml b/resources/units/ground_units/Blitz_36-6700A.yaml deleted file mode 100644 index e694cb7c5..000000000 --- a/resources/units/ground_units/Blitz_36-6700A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck Opel Blitz: null -hit_points: 3 diff --git a/resources/units/ground_units/CCKW_353.yaml b/resources/units/ground_units/CCKW_353.yaml deleted file mode 100644 index a74479cf5..000000000 --- a/resources/units/ground_units/CCKW_353.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck GMC "Jimmy" 6x6 Truck: null -hit_points: 3 diff --git a/resources/units/ground_units/Centaur_IV.yaml b/resources/units/ground_units/Centaur_IV.yaml deleted file mode 100644 index bec34d5c7..000000000 --- a/resources/units/ground_units/Centaur_IV.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Tank -description: 'The Cromwell tank, officially Tank, Cruiser, Mk VIII, Cromwell (A27M), - was one of the series of cruiser tanks fielded by Britain in the Second World War. - Named after the English Civil War leader Oliver Cromwell, the Cromwell was the first - tank put into service by the British to combine high speed from a powerful and reliable - engine (the Rolls-Royce Meteor), and reasonable armour. ' -introduced: 1944 -manufacturer: Leyland -origin: UK -price: 10 -role: Cruiser Tank -variants: - A27L Cruiser Tank MK VIII Centaur IV: {} -hit_points: 12 diff --git a/resources/units/ground_units/Challenger2.yaml b/resources/units/ground_units/Challenger2.yaml deleted file mode 100644 index 9d1a0a95c..000000000 --- a/resources/units/ground_units/Challenger2.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Tank -description: The FV4034 Challenger 2 is a third generation British main battle tank - (MBT) in service with the armies of the United Kingdom and Oman. It has seen operational - service in Bosnia and Herzegovina, Kosovo and Iraq. To date, the only time the - tank has been destroyed during operations was by another Challenger 2 in a "blue - on blue" (friendly fire) incident at Basra in 2003 when the destroyed tank had its - hatch open at the time of the incident. -introduced: 1998 -manufacturer: Vickers Defence Systems -origin: UK -price: 25 -role: Main Battle Tank -variants: - FV4034 Challenger 2: {} -hit_points: 32 diff --git a/resources/units/ground_units/Chieftain_mk3.yaml b/resources/units/ground_units/Chieftain_mk3.yaml deleted file mode 100644 index 966a28e0e..000000000 --- a/resources/units/ground_units/Chieftain_mk3.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Tank -description: - The FV4201 Chieftain was the main battle tank of the United Kingdom during - the 1960s, 1970s and 1980s. -introduced: 1966 -manufacturer: Leyland Motors -origin: UK -price: 20 -role: Main Battle Tank -variants: - Chieftain Mk.3: {} -hit_points: 20 diff --git a/resources/units/ground_units/Churchill_VII.yaml b/resources/units/ground_units/Churchill_VII.yaml deleted file mode 100644 index 334b7e188..000000000 --- a/resources/units/ground_units/Churchill_VII.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Tank -description: The Tank, Infantry, Mk IV (A22) Churchill was a British heavy infantry - tank used in the Second World War, best known for its heavy armour, large longitudinal - chassis with all-around tracks with multiple bogies, its ability to climb steep - slopes, and its use as the basis of many specialist vehicles. It was one of the - heaviest Allied tanks of the war. -introduced: 1944 -manufacturer: Vauxhall Motors -origin: UK -price: 16 -role: Infantry Tank -variants: - A22 Infantry Tank MK IV Churchill VII: {} -hit_points: 13 diff --git a/resources/units/ground_units/Cobra.yaml b/resources/units/ground_units/Cobra.yaml deleted file mode 100644 index 2b8578e23..000000000 --- a/resources/units/ground_units/Cobra.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Recon -description: 'The Cobra (Turkish: Kobra) is an armoured tactical vehicle developed - by Turkish firm Otokar.' -introduced: 1997 -manufacturer: Otokar -origin: Turkey -price: 4 -role: Recon -variants: - Cobra: {} -hit_points: 2 diff --git a/resources/units/ground_units/Cromwell_IV.yaml b/resources/units/ground_units/Cromwell_IV.yaml deleted file mode 100644 index f075dc021..000000000 --- a/resources/units/ground_units/Cromwell_IV.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Tank -description: 'The Cromwell tank, officially Tank, Cruiser, Mk VIII, Cromwell (A27M), - was one of the series of cruiser tanks fielded by Britain in the Second World War. - Named after the English Civil War leader Oliver Cromwell, the Cromwell was the first - tank put into service by the British to combine high speed from a powerful and reliable - engine (the Rolls-Royce Meteor), and reasonable armour. ' -introduced: 1944 -manufacturer: Birmingham Railway Carriage and Wagon Company -origin: UK -price: 12 -role: Cruiser Tank -variants: - A27M Cruiser Tank MK VIII Cromwell IV: {} -hit_points: 12 diff --git a/resources/units/ground_units/Daimler_AC.yaml b/resources/units/ground_units/Daimler_AC.yaml deleted file mode 100644 index 4f6c904c0..000000000 --- a/resources/units/ground_units/Daimler_AC.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Recon -description: The Daimler Armoured Car was a successful British armoured car design - of the Second World War that continued in service into the 1950s. It was designed - for armed reconnaissance and liaison purposes. During the postwar era, it doubled - as an internal security vehicle in a number of countries. Former British Daimler - armoured cars were exported to various Commonwealth of Nations member states throughout - the 1950s and 1960s. In 2012, some were still being operated by the Qatari Army. -introduced: 1941 -manufacturer: Daimler -origin: UK -price: 8 -role: Recon -variants: - Daimler Armoured Car Mk I: {} -hit_points: 4 diff --git a/resources/units/ground_units/Dog Ear radar.yaml b/resources/units/ground_units/Dog Ear radar.yaml deleted file mode 100644 index 629be7059..000000000 --- a/resources/units/ground_units/Dog Ear radar.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 10 -variants: - MCC-SR Sborka "Dog Ear" SR: null -hit_points: 3 diff --git a/resources/units/ground_units/ERC.yaml b/resources/units/ground_units/ERC.yaml deleted file mode 100644 index dda291942..000000000 --- a/resources/units/ground_units/ERC.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Recon -description: "The Panhard ERC (Engin \xE0 Roues, Canon) is a French six-wheeled armoured\ - \ car which is highly mobile and amphibious with an option of being NBC-proof." -introduced: 1975 -manufacturer: GIAT Industries -origin: France -price: 12 -role: Recon Vehicle -variants: - Panhard: {} diff --git a/resources/units/ground_units/Elefant_SdKfz_184.yaml b/resources/units/ground_units/Elefant_SdKfz_184.yaml deleted file mode 100644 index e571d04ed..000000000 --- a/resources/units/ground_units/Elefant_SdKfz_184.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: ATGM -description: - The Elefant (German for "elephant") was a heavy tank destroyer used by German - Wehrmacht Panzerjäger during World War II. Ninety-one units were built in 1943 - under the name Ferdinand, after its designer Ferdinand Porsche, using tank - hulls produced for the Tiger I tank design abandoned in favour of a Henschel - design. -introduced: 1944 -manufacturer: Porsche/Nibelungenwerk -origin: Germany -price: 18 -role: Tank Destroyer -variants: - Sd.Kfz.184 Elefant: {} -hit_points: 20 diff --git a/resources/units/ground_units/FPS-117 Dome.yaml b/resources/units/ground_units/FPS-117 Dome.yaml deleted file mode 100644 index a2ea4cced..000000000 --- a/resources/units/ground_units/FPS-117 Dome.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 30 -variants: - EWR AN/FPS-117 Radar (domed): null -hit_points: 2 diff --git a/resources/units/ground_units/FPS-117.yaml b/resources/units/ground_units/FPS-117.yaml deleted file mode 100644 index 7d769fb09..000000000 --- a/resources/units/ground_units/FPS-117.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 30 -variants: - EWR AN/FPS-117 Radar: null -hit_points: 2 diff --git a/resources/units/ground_units/Fire Can radar.yaml b/resources/units/ground_units/Fire Can radar.yaml deleted file mode 100644 index 5c5b757bc..000000000 --- a/resources/units/ground_units/Fire Can radar.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 8 -variants: - AAA SON-9 Fire Can: null diff --git a/resources/units/ground_units/Flakscheinwerfer_37.yaml b/resources/units/ground_units/Flakscheinwerfer_37.yaml deleted file mode 100644 index 9f4a910f7..000000000 --- a/resources/units/ground_units/Flakscheinwerfer_37.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchLight -price: 4 -variants: - SL Flakscheinwerfer 37: null -hit_points: 2 diff --git a/resources/units/ground_units/FuMG-401.yaml b/resources/units/ground_units/FuMG-401.yaml deleted file mode 100644 index e4ebd6166..000000000 --- a/resources/units/ground_units/FuMG-401.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: EarlyWarningRadar -price: 25 -variants: - EWR FuMG-401 Freya LZ: null -hit_points: 30 diff --git a/resources/units/ground_units/GAZ-3307.yaml b/resources/units/ground_units/GAZ-3307.yaml deleted file mode 100644 index 9b9ec1f99..000000000 --- a/resources/units/ground_units/GAZ-3307.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 2 -variants: - Truck GAZ-3307: null -hit_points: 1 diff --git a/resources/units/ground_units/GAZ-3308.yaml b/resources/units/ground_units/GAZ-3308.yaml deleted file mode 100644 index b519a3bd9..000000000 --- a/resources/units/ground_units/GAZ-3308.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck GAZ-3308: null -hit_points: 1 diff --git a/resources/units/ground_units/GAZ-66.yaml b/resources/units/ground_units/GAZ-66.yaml deleted file mode 100644 index 629e54f44..000000000 --- a/resources/units/ground_units/GAZ-66.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck GAZ-66: null -hit_points: 2 diff --git a/resources/units/ground_units/Gepard.yaml b/resources/units/ground_units/Gepard.yaml deleted file mode 100644 index 38e21b9fc..000000000 --- a/resources/units/ground_units/Gepard.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: AAA -description: The Flugabwehrkanonenpanzer Gepard ("anti-aircraft cannon tank Cheetah", - better known as the Flakpanzer Gepard) is an all-weather-capable German self-propelled - anti-aircraft gun (SPAAG).[1] It was developed in the 1960s and fielded in the 1970s, - and has been upgraded several times with the latest electronics. It constituted - a cornerstone of the air defence of the German Army (Bundeswehr) and a number of - other NATO countries. In Germany, the Gepard was phased out in late 2010 and replaced - by Wiesel 2 Ozelot Leichtes Flugabwehrsystem (LeFlaSys) with four FIM-92 Stinger - or LFK NG missile launchers. -introduced: 1976 -manufacturer: Krauss-Maffei -origin: West Germany -price: 24 -role: Self-Propelled Anti-Aircraft Gun -variants: - Flakpanzer Gepard: {} -hit_points: 20 diff --git a/resources/units/ground_units/Grad-URAL.yaml b/resources/units/ground_units/Grad-URAL.yaml deleted file mode 100644 index e8ec8ad35..000000000 --- a/resources/units/ground_units/Grad-URAL.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Artillery -description: "The BM-21 \"Grad\" (Russian: \u0411\u041C-21 \"\u0413\u0440\u0430\u0434\ - \", lit.\u2009'hail') is a Soviet truck-mounted 122 mm multiple rocket launcher." -introduced: 1963 -manufacturer: Splav -origin: USSR/Russia -price: 15 -role: Multiple-Launch Rocket System -variants: - BM-21 Grad: {} -hit_points: 2 diff --git a/resources/units/ground_units/Grad_FDDM.yaml b/resources/units/ground_units/Grad_FDDM.yaml deleted file mode 100644 index 64b1d3895..000000000 --- a/resources/units/ground_units/Grad_FDDM.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Artillery -price: 4 -variants: - Grad MRL FDDM (FC): null -hit_points: 3 diff --git a/resources/units/ground_units/HEMTT_C-RAM_Phalanx.yaml b/resources/units/ground_units/HEMTT_C-RAM_Phalanx.yaml deleted file mode 100644 index df2e7a9a2..000000000 --- a/resources/units/ground_units/HEMTT_C-RAM_Phalanx.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: AAA -description: "The Centurion C-RAM Land Phalanx Weapon System (LPWS) is a sophisticated and\ - \ highly effective close-in defense system designed to protect military installations,\ - \ forward operating bases, and critical infrastructure from incoming rocket, artillery,\ - \ and mortar (RAM) threats. Developed to provide a rapid response to such threats, the\ - \ LPWS combines radar and computerized tracking systems with a 20mm M61A1 Gatling gun,\ - \ which is capable of engaging and neutralizing incoming projectiles. The LPWS is\ - \ particularly adept at countering the dangers posed by asymmetric warfare, as it can\ - \ swiftly detect, track, and eliminate RAM threats, providing a critical layer of\ - \ protection for both military and civilian assets in vulnerable areas." - -introduced: 2006 -manufacturer: Raytheon -origin: USA -price: 12 -role: Self-Propelled Anti-Aircraft Gun -variants: - Centurion C-RAM LPWS: {} -hit_points: 3 diff --git a/resources/units/ground_units/HL_B8M1.yaml b/resources/units/ground_units/HL_B8M1.yaml deleted file mode 100644 index ed1a294ab..000000000 --- a/resources/units/ground_units/HL_B8M1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Artillery -price: 10 -role: Multiple-Launch Rocket System -variants: - MLRS HL with B8M1 80mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/HL_DSHK.yaml b/resources/units/ground_units/HL_DSHK.yaml deleted file mode 100644 index 330f2c25f..000000000 --- a/resources/units/ground_units/HL_DSHK.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: APC -price: 4 -role: Recon -variants: - Scout HL with DSHK 12.7mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/HL_KORD.yaml b/resources/units/ground_units/HL_KORD.yaml deleted file mode 100644 index ff5e90136..000000000 --- a/resources/units/ground_units/HL_KORD.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: APC -price: 4 -role: Recon -variants: - Scout HL with KORD 12.7mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/HL_ZU-23.yaml b/resources/units/ground_units/HL_ZU-23.yaml deleted file mode 100644 index 81b044d1f..000000000 --- a/resources/units/ground_units/HL_ZU-23.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 6 -variants: - SPAAA HL with ZU-23: null -hit_points: 1 diff --git a/resources/units/ground_units/HQ-7_LN_SP.yaml b/resources/units/ground_units/HQ-7_LN_SP.yaml deleted file mode 100644 index d02f7e433..000000000 --- a/resources/units/ground_units/HQ-7_LN_SP.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Launcher -description: "The HQ-7 (FM-80) (Chinese: \u7EA2\u65D7; pinyin: h\xF3ng q\xED, \"red\ - \ flag\" or \"red banner\") is a Chinese short-range air defense missile reverse\ - \ engineered from the French Crotale. The missile is deployed on both ships and\ - \ land-based vehicles. China revealed the export version, FM-80, in the 1989 Dubai\ - \ Air Show. Unit cost is around $162,000 per launcher and $24,500 per missile." -introduced: 1983 -manufacturer: Academy for Defense -origin: China -price: 20 -role: Shorad -variants: - HQ-7 Launcher: {} -hit_points: 2 diff --git a/resources/units/ground_units/HQ-7_STR_SP.yaml b/resources/units/ground_units/HQ-7_STR_SP.yaml deleted file mode 100644 index c8ff040bb..000000000 --- a/resources/units/ground_units/HQ-7_STR_SP.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchTrackRadar -price: 24 -variants: - HQ-7 Self-Propelled STR: null -hit_points: 2 diff --git a/resources/units/ground_units/HQ_2_Guideline_LN.yaml b/resources/units/ground_units/HQ_2_Guideline_LN.yaml deleted file mode 100644 index d6545502c..000000000 --- a/resources/units/ground_units/HQ_2_Guideline_LN.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 8 -variants: - SAM HQ-2 LN SM-90: null diff --git a/resources/units/ground_units/Hawk cwar.yaml b/resources/units/ground_units/Hawk cwar.yaml deleted file mode 100644 index ccc97ff17..000000000 --- a/resources/units/ground_units/Hawk cwar.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SpecializedRadar -price: 20 -variants: - SAM Hawk CWAR AN/MPQ-55: null -hit_points: 2 diff --git a/resources/units/ground_units/Hawk ln.yaml b/resources/units/ground_units/Hawk ln.yaml deleted file mode 100644 index 1ec22335c..000000000 --- a/resources/units/ground_units/Hawk ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 8 -variants: - SAM Hawk LN M192: null -hit_points: 2 diff --git a/resources/units/ground_units/Hawk pcp.yaml b/resources/units/ground_units/Hawk pcp.yaml deleted file mode 100644 index f91b4837d..000000000 --- a/resources/units/ground_units/Hawk pcp.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: CommandPost -price: 14 -variants: - SAM Hawk Platoon Command Post (PCP): null -hit_points: 2 diff --git a/resources/units/ground_units/Hawk sr.yaml b/resources/units/ground_units/Hawk sr.yaml deleted file mode 100644 index 48d377293..000000000 --- a/resources/units/ground_units/Hawk sr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 18 -variants: - SAM Hawk SR (AN/MPQ-50): null -hit_points: 2 diff --git a/resources/units/ground_units/Hawk tr.yaml b/resources/units/ground_units/Hawk tr.yaml deleted file mode 100644 index dbf64bcc2..000000000 --- a/resources/units/ground_units/Hawk tr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 14 -variants: - SAM Hawk TR (AN/MPQ-46): null -hit_points: 2 diff --git a/resources/units/ground_units/Horch_901_typ_40_kfz_21.yaml b/resources/units/ground_units/Horch_901_typ_40_kfz_21.yaml deleted file mode 100644 index ac3213e8b..000000000 --- a/resources/units/ground_units/Horch_901_typ_40_kfz_21.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - LUV Horch 901 Staff Car: null -hit_points: 3 diff --git a/resources/units/ground_units/Igla manpad INS.yaml b/resources/units/ground_units/Igla manpad INS.yaml deleted file mode 100644 index a1524480a..000000000 --- a/resources/units/ground_units/Igla manpad INS.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - MANPADS SA-18 Igla "Grouse" Ins: null -hit_points: 1 diff --git a/resources/units/ground_units/Infantry AK Ins.yaml b/resources/units/ground_units/Infantry AK Ins.yaml deleted file mode 100644 index 6a384a6e0..000000000 --- a/resources/units/ground_units/Infantry AK Ins.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 3 -variants: - Insurgent AK-74: null -hit_points: 1 diff --git a/resources/units/ground_units/Infantry AK.yaml b/resources/units/ground_units/Infantry AK.yaml deleted file mode 100644 index 25fb2b3d1..000000000 --- a/resources/units/ground_units/Infantry AK.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 4 -variants: - Infantry AK-74 Rus: null -hit_points: 1 diff --git a/resources/units/ground_units/JTACFP.yaml b/resources/units/ground_units/JTACFP.yaml deleted file mode 100644 index 4c12fa175..000000000 --- a/resources/units/ground_units/JTACFP.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Infantry -price: 1 -variants: - Infantry Soldier JTAC: null diff --git a/resources/units/ground_units/JagdPz_IV.yaml b/resources/units/ground_units/JagdPz_IV.yaml deleted file mode 100644 index b6acbf21f..000000000 --- a/resources/units/ground_units/JagdPz_IV.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: ATGM -description: The Jagdpanzer IV, Sd.Kfz. 162, was a German tank destroyer based on - the Panzer IV chassis. -introduced: 1944 -manufacturer: Vomag -origin: Germany -price: 11 -role: Tank Destroyer -variants: - Jagdpanzer IV: {} -hit_points: 15 diff --git a/resources/units/ground_units/Jagdpanther_G1.yaml b/resources/units/ground_units/Jagdpanther_G1.yaml deleted file mode 100644 index eebe830d8..000000000 --- a/resources/units/ground_units/Jagdpanther_G1.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: ATGM -description: 'The Jagdpanther (German: "hunting Panther"), Sd.Kfz. 173, was a tank - destroyer (Jagdpanzer, a self-propelled anti-tank gun) built by Germany during World - War II. The Jagdpanther combined the 8.8 cm Pak 43 anti-tank gun, similar to the - main gun of the Tiger II, and the armor and suspension of the Panther chassis.' -introduced: 1944 -manufacturer: MIAG/MNH/MBA -origin: Germany -price: 18 -role: Tank Destroyer -variants: - Jagdpanther G1: {} -hit_points: 15 diff --git a/resources/units/ground_units/KAMAZ Truck.yaml b/resources/units/ground_units/KAMAZ Truck.yaml deleted file mode 100644 index 7b14b0771..000000000 --- a/resources/units/ground_units/KAMAZ Truck.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck KAMAZ 43101: null -hit_points: 2 diff --git a/resources/units/ground_units/KDO_Mod40.yaml b/resources/units/ground_units/KDO_Mod40.yaml deleted file mode 100644 index 2c48621f1..000000000 --- a/resources/units/ground_units/KDO_Mod40.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 8 -variants: - AAA SP Kdo.G.40: null -hit_points: 1 diff --git a/resources/units/ground_units/KS-19.yaml b/resources/units/ground_units/KS-19.yaml deleted file mode 100644 index b630876d7..000000000 --- a/resources/units/ground_units/KS-19.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 10 -variants: - AAA 100mm KS-19: null -hit_points: 4 diff --git a/resources/units/ground_units/Kamikaze.yaml b/resources/units/ground_units/Kamikaze.yaml deleted file mode 100644 index 1e9359dea..000000000 --- a/resources/units/ground_units/Kamikaze.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 6 -variants: - DIM' KAMIKAZE: null diff --git a/resources/units/ground_units/Kub 1S91 str.yaml b/resources/units/ground_units/Kub 1S91 str.yaml deleted file mode 100644 index 08c8dc496..000000000 --- a/resources/units/ground_units/Kub 1S91 str.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchTrackRadar -price: 22 -variants: - SAM SA-6 Kub "Straight Flush" STR: null -hit_points: 4 diff --git a/resources/units/ground_units/Kub 2P25 ln.yaml b/resources/units/ground_units/Kub 2P25 ln.yaml deleted file mode 100644 index 85786f66f..000000000 --- a/resources/units/ground_units/Kub 2P25 ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TELAR -price: 20 -variants: - SAM SA-6 Kub "Gainful" TEL: null -hit_points: 4 diff --git a/resources/units/ground_units/Kubelwagen_82.yaml b/resources/units/ground_units/Kubelwagen_82.yaml deleted file mode 100644 index 1d7666dc8..000000000 --- a/resources/units/ground_units/Kubelwagen_82.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - LUV Kubelwagen 82: null -hit_points: 2 diff --git a/resources/units/ground_units/LARC-V.yaml b/resources/units/ground_units/LARC-V.yaml deleted file mode 100644 index ed81fc7f1..000000000 --- a/resources/units/ground_units/LARC-V.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Logistics -price: 2 -variants: - LARC-V: null diff --git a/resources/units/ground_units/LAV-25.yaml b/resources/units/ground_units/LAV-25.yaml deleted file mode 100644 index eda4a5f6a..000000000 --- a/resources/units/ground_units/LAV-25.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Recon -description: The LAV-25 (Light Armored Vehicle) is an eight-wheeled amphibious armored - reconnaissance vehicle built by General Dynamics Land Systems and used by the United - States Marine Corps and the United States Army. -introduced: 1983 -manufacturer: General Dynamics -origin: USA -price: 7 -role: Amphibious Armoured Car -variants: - LAV-25: {} -hit_points: 4 diff --git a/resources/units/ground_units/Land_Rover_101_FC.yaml b/resources/units/ground_units/Land_Rover_101_FC.yaml deleted file mode 100644 index 89e06d943..000000000 --- a/resources/units/ground_units/Land_Rover_101_FC.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - Truck Land Rover 101 FC: null -hit_points: 3 diff --git a/resources/units/ground_units/Land_Rover_109_S3.yaml b/resources/units/ground_units/Land_Rover_109_S3.yaml deleted file mode 100644 index 99da008b6..000000000 --- a/resources/units/ground_units/Land_Rover_109_S3.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 1 -variants: - LUV Land Rover 109: null -hit_points: 3 diff --git a/resources/units/ground_units/LeFH_18-40-105.yaml b/resources/units/ground_units/LeFH_18-40-105.yaml deleted file mode 100644 index 37557cadb..000000000 --- a/resources/units/ground_units/LeFH_18-40-105.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Artillery -description: -introduced: -manufacturer: -origin: -price: 5 -role: Field Howitzer -variants: - FH LeFH-18 105mm: {} -hit_points: 2 diff --git a/resources/units/ground_units/Leclerc.yaml b/resources/units/ground_units/Leclerc.yaml deleted file mode 100644 index d7b20fb2b..000000000 --- a/resources/units/ground_units/Leclerc.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: Tank -description: "The Leclerc tank (French: char Leclerc) is a main battle tank (MBT)\ - \ built by GIAT, now Nexter of France. It was named in honour of General Philippe\ - \ Leclerc de Hauteclocque, who led the French element of the drive towards Paris\ - \ while in command of the Free French 2nd Armoured Division (2e DB) in World War\ - \ II. The designation AMX-56 \u2013 while very popular \u2013 is incorrect. During\ - \ the Iron spear exercise, October 2019, Leclerc tanks crewed by the Lynx 6 Tactical\ - \ Inter-Service Sub-Group (S-GTIA) participated in an inter-alliance exercise and\ - \ surpassed the American M1A2 Abrams, German, Spanish and Norwegian Leopard 2s,\ - \ Italian Ariete C1 and Polish P91." -introduced: 1993 -manufacturer: GIAT Industries -origin: France -price: 25 -role: Main Battle Tank -variants: - "Leclerc S\xE9ries 2": {} -hit_points: 32 diff --git a/resources/units/ground_units/Leclerc_XXI.yaml b/resources/units/ground_units/Leclerc_XXI.yaml deleted file mode 100644 index 53efc0ed7..000000000 --- a/resources/units/ground_units/Leclerc_XXI.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: Tank -description: "The Leclerc tank (French: char Leclerc) is a main battle tank (MBT)\ - \ built by GIAT, now Nexter of France. It was named in honour of General Philippe\ - \ Leclerc de Hauteclocque, who led the French element of the drive towards Paris\ - \ while in command of the Free French 2nd Armoured Division (2e DB) in World War\ - \ II. The designation AMX-56 \u2013 while very popular \u2013 is incorrect. During\ - \ the Iron spear exercise, October 2019, Leclerc tanks crewed by the Lynx 6 Tactical\ - \ Inter-Service Sub-Group (S-GTIA) participated in an inter-alliance exercise and\ - \ surpassed the American M1A2 Abrams, German, Spanish and Norwegian Leopard 2s,\ - \ Italian Ariete C1 and Polish P91." -introduced: 2001 -manufacturer: GIAT Industries -origin: France -price: 35 -role: Main Battle Tank -variants: - Leclerc_XXI: {} diff --git a/resources/units/ground_units/Leopard-2.yaml b/resources/units/ground_units/Leopard-2.yaml deleted file mode 100644 index cfc122987..000000000 --- a/resources/units/ground_units/Leopard-2.yaml +++ /dev/null @@ -1,20 +0,0 @@ -class: Tank -description: The Leopard 2 is a main battle tank developed by Krauss-Maffei in the - 1970s for the West German Army. The tank first entered service in 1979 and succeeded - the earlier Leopard 1 as the main battle tank of the German Army. It is armed with - a 120 mm smoothbore cannon, and is powered by a V-12 twin-turbo diesel engine. Various - versions have served in the armed forces of Germany and 12 other European countries, - as well as several non-European nations, including Canada, Chile, Indonesia, Singapore, - and Turkey. The Leopard 2 was used in Kosovo with the German Army, and has seen - action in Afghanistan with the Dutch, Danish and Canadian contributions to the International - Security Assistance Force, as well as seeing action in Syria with the Turkish Armed - Forces. -introduced: 1985 -manufacturer: Krauss-Maffei -origin: Germany -price: 25 -role: Main Battle Tank -variants: - Leopard 2: {} - Leopard 2A6M: {} -hit_points: 32 diff --git a/resources/units/ground_units/Leopard-2A5.yaml b/resources/units/ground_units/Leopard-2A5.yaml deleted file mode 100644 index ce6c19cec..000000000 --- a/resources/units/ground_units/Leopard-2A5.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The Leopard 2 is a main battle tank developed by Krauss-Maffei in the - 1970s for the West German Army. The tank first entered service in 1979 and succeeded - the earlier Leopard 1 as the main battle tank of the German Army. It is armed with - a 120 mm smoothbore cannon, and is powered by a V-12 twin-turbo diesel engine. Various - versions have served in the armed forces of Germany and 12 other European countries, - as well as several non-European nations, including Canada, Chile, Indonesia, Singapore, - and Turkey. The Leopard 2 was used in Kosovo with the German Army, and has seen - action in Afghanistan with the Dutch, Danish and Canadian contributions to the International - Security Assistance Force, as well as seeing action in Syria with the Turkish Armed - Forces. -introduced: 1995 -manufacturer: Krauss-Maffei -origin: Germany -price: 22 -role: Main Battle Tank -variants: - Leopard 2A5: {} -hit_points: 32 diff --git a/resources/units/ground_units/Leopard1A3.yaml b/resources/units/ground_units/Leopard1A3.yaml deleted file mode 100644 index 4320d2b10..000000000 --- a/resources/units/ground_units/Leopard1A3.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The Leopard (or Leopard 1) is a main battle tank designed and produced - by Porsche in West Germany that first entered service in 1965. Developed in an era - when HEAT warheads were thought to make conventional heavy armour of limited value, - the Leopard focused on firepower in the form of the German-built version of the - British L7 105-mm gun, and improved cross-country performance that was unmatched - by other designs of the era. The Leopard quickly became a standard of many European - militaries, and eventually served as the main battle tank in over a dozen countries - worldwide, with West Germany, Italy and the Netherlands being the largest operators - until their retirement. Currently, the largest operators are Greece, with 520 vehicles, - Turkey, with 397 vehicles and Brazil with 378 vehicles. -introduced: 1974 -manufacturer: Krauss-Maffei -origin: Germany -price: 18 -role: Main Battle Tank -variants: - Leopard 1A3: {} -hit_points: 20 diff --git a/resources/units/ground_units/M 818.yaml b/resources/units/ground_units/M 818.yaml deleted file mode 100644 index 88049531f..000000000 --- a/resources/units/ground_units/M 818.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 3 -variants: - Truck M818 6x6: null -hit_points: 2 diff --git a/resources/units/ground_units/M-1 Abrams.yaml b/resources/units/ground_units/M-1 Abrams.yaml deleted file mode 100644 index 829b4f2f1..000000000 --- a/resources/units/ground_units/M-1 Abrams.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The M1 Abrams is a third-generation American main battle tank designed - by Chrysler Defense (now General Dynamics Land Systems)[9] and named for General - Creighton Abrams. Conceived for modern armored ground warfare and now one of the - heaviest tanks in service at nearly 68 short tons. The M1 Abrams entered service - in 1980 and currently serves as the main battle tank of the United States Army and - Marine Corps. The export version is used by the armies of Egypt, Kuwait, Saudi Arabia, - Australia, and Iraq. The Abrams was first used in combat in the Persian Gulf War - and has seen combat in both the War in Afghanistan and Iraq War under U.S. service, - while Iraqi Abrams tanks have seen action in the war against ISIL and have seen - use by Saudi Arabia during the Yemeni Civil War. -introduced: 1992 -manufacturer: General Dynamics -origin: USA -price: 25 -role: Main Battle Tank -variants: - M1A2 Abrams: {} -hit_points: 32 diff --git a/resources/units/ground_units/M-109.yaml b/resources/units/ground_units/M-109.yaml deleted file mode 100644 index 3987aec76..000000000 --- a/resources/units/ground_units/M-109.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Artillery -description: The M109 is an American 155 mm turreted self-propelled howitzer, first - introduced in the early 1960s to replace the M44. -introduced: 1994 -manufacturer: United Defense -origin: USA -price: 25 -role: Self-Propelled Gun -variants: - M109A6 Paladin: {} -hit_points: 3 diff --git a/resources/units/ground_units/M-113.yaml b/resources/units/ground_units/M-113.yaml deleted file mode 100644 index 5d160d6c5..000000000 --- a/resources/units/ground_units/M-113.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: APC -description: The M113 is a fully tracked armored personnel carrier (APC) that was - developed and produced by the Food Machinery and Chemical Corporation (FMC). The - M113 was sent to United States Army Europe to replace the mechanized infantry's - M59 APCs from 1961. The M113 was first used in combat in April 1962 after the United - States provided the South Vietnamese Army (ARVN) with heavy weaponry such as the - M113, under the Military Assistance Command, Vietnam (MACV) program. Eventually, - the M113 was the most widely used armored vehicle of the U.S. Army in the Vietnam - War and was used to break through heavy thickets in the midst of the jungle to attack - and overrun enemy positions. About 80.000 have been build. -introduced: 1960 -manufacturer: Food Machinery Corp -origin: USA -price: 6 -role: Armoured Personnel Carrier -variants: - M113: {} -hit_points: 3 diff --git a/resources/units/ground_units/M-2 Bradley.yaml b/resources/units/ground_units/M-2 Bradley.yaml deleted file mode 100644 index 74d10dacb..000000000 --- a/resources/units/ground_units/M-2 Bradley.yaml +++ /dev/null @@ -1,21 +0,0 @@ -class: IFV -description: 'The M2 Bradley, or Bradley IFV, is an American infantry fighting vehicle - that is a member of the Bradley Fighting Vehicle family. It is manufactured by BAE - Systems Land & Armaments, which was formerly United Defense. The Bradley is designed - for reconnaissance and to transport a squad of infantry, providing them protection - from small arms fire, while also providing firepower to both suppress and eliminate - most threats to friendly infantry. It is designed to be highly maneuverable and - to be fast enough to keep up with heavy armor during an advance. The M2 holds a - crew of three: a commander, a gunner and a driver, as well as six fully equipped - soldiers. In the year 2000 the total cost of the program was $5,664,100,000 for - 1602 units, giving an average unit cost of $3,166,000. If you want to know more - than you ever wanted about the Bradley, watch the film ''The Pentagon Wars'', its - great!' -introduced: 1988 -manufacturer: United Defense -origin: USA -price: 12 -role: Infantry Fighting Vehicle -variants: - M2A2 Bradley: {} -hit_points: 6 diff --git a/resources/units/ground_units/M-60.yaml b/resources/units/ground_units/M-60.yaml deleted file mode 100644 index d4568de7c..000000000 --- a/resources/units/ground_units/M-60.yaml +++ /dev/null @@ -1,26 +0,0 @@ -class: Tank -description: "The M60 reached operational capability with fielding to US Army units\ - \ in Europe beginning in December 1960. The first combat usage of the M60 was with\ - \ Israel during the 1973 Yom Kippur War where it saw service under the \"Magach\ - \ 6\" designation, performing well in combat against comparable tanks such as the\ - \ T-62. In 1982 the Israelis once again used the M60 during the 1982 Lebanon War,\ - \ equipped with upgrades such as explosive reactive armor to defend against guided\ - \ missiles that proved very effective at destroying tanks. The M60 also saw use\ - \ in 1983 with Operation Urgent Fury, supporting US Marines in an amphibious assault\ - \ into Grenada. M60s delivered to Iran also served in the Iran\u2013Iraq War. The\ - \ United States' largest deployment of M60s was in the 1991 Gulf War, where the\ - \ US Marines equipped with M60A1s effectively defeated Iraqi armored forces, including\ - \ T-72 tanks. The United States readily retired the M60 from front-line combat after\ - \ Operation Desert Storm, with the last tanks being retired from National Guard\ - \ service in 1997.[16] M60-series vehicles continue in front-line service with a\ - \ number of countries' militaries, though most of these have been highly modified\ - \ and had their firepower, mobility and protection upgraded to increase their combat\ - \ effectiveness on the modern battlefield." -introduced: 1960 -manufacturer: General Dynamics -origin: USA -price: 16 -role: Main Battle Tank -variants: - M60A3 "Patton": {} -hit_points: 20 diff --git a/resources/units/ground_units/M1043 HMMWV Armament.yaml b/resources/units/ground_units/M1043 HMMWV Armament.yaml deleted file mode 100644 index 1632d2bf8..000000000 --- a/resources/units/ground_units/M1043 HMMWV Armament.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Recon -description: 'The High Mobility Multipurpose Wheeled Vehicle (HMMWV; colloquial: Humvee) - is a family of light, four-wheel drive, military trucks and utility vehicles produced - by AM General.' -introduced: 1983 -manufacturer: AM General -origin: USA -price: 2 -role: Recon -variants: - M1043 HMMWV (M2 HMG): {} -hit_points: 2 diff --git a/resources/units/ground_units/M1045 HMMWV TOW.yaml b/resources/units/ground_units/M1045 HMMWV TOW.yaml deleted file mode 100644 index 820f571dd..000000000 --- a/resources/units/ground_units/M1045 HMMWV TOW.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: ATGM -description: 'The High Mobility Multipurpose Wheeled Vehicle (HMMWV; colloquial: Humvee) - is a family of light, four-wheel drive, military trucks and utility vehicles produced - by AM General. This verison carries a TOW for ATGM.' -introduced: 1983 -manufacturer: AM General -origin: USA -price: 8 -role: Armoured Car -variants: - M1045 HMMWV (BGM-71 TOW): {} -hit_points: 2 diff --git a/resources/units/ground_units/M1097 Avenger.yaml b/resources/units/ground_units/M1097 Avenger.yaml deleted file mode 100644 index 64446d737..000000000 --- a/resources/units/ground_units/M1097 Avenger.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: SHORAD -description: The Avenger Air Defense System, designated AN/TWQ-1 under the Joint Electronics - Type Designation System, is an American self-propelled surface-to-air missile system - which provides mobile, short-range air defense protection for ground units against - cruise missiles, unmanned aerial vehicles, low-flying fixed-wing aircraft, and helicopters. -introduced: 1990 -manufacturer: Boeing -origin: USA -price: 20 -role: Self-Propelled Surface-to-Air Missile Launcher -variants: - M1097 Heavy HMMWV Avenger: {} -hit_points: 2 diff --git a/resources/units/ground_units/M10_GMC.yaml b/resources/units/ground_units/M10_GMC.yaml deleted file mode 100644 index 3a70c1031..000000000 --- a/resources/units/ground_units/M10_GMC.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: ATGM -description: The M10 tank destroyer was an American tank destroyer of World War II. - The M10 was numerically the most important U.S. tank destroyer of World War II. - It combined thin but sloped armor with the M4's reliable drivetrain and a reasonably - potent anti-tank weapon mounted in an open-topped turret. Despite its obsolescence - in the face of newer German tanks like the Panther and the introduction of more - powerful and better-designed types as replacements, the M10 remained in service - until the end of the war. -introduced: 1942 -manufacturer: Fisher/Ford Motor Company -origin: USA -price: 14 -role: Tank Destroyer -variants: - 3in SPM M10 Achilles Mk II: {} - M10 3-inch Gun Motor Carriage: {} -hit_points: 10 diff --git a/resources/units/ground_units/M1126 Stryker ICV.yaml b/resources/units/ground_units/M1126 Stryker ICV.yaml deleted file mode 100644 index 152389a23..000000000 --- a/resources/units/ground_units/M1126 Stryker ICV.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: APC -description: 'The ICV (Infantry Carrier Vehicle) Stryker is a family of eight-wheeled - armored fighting vehicles derived from the Canadian LAV III. ' -introduced: 2002 -manufacturer: General Dynamics -origin: USA -price: 10 -role: Armoured Personnel Carrier -variants: - M1126 Stryker ICV (M2 HMG): {} -hit_points: 4 diff --git a/resources/units/ground_units/M1128 Stryker MGS.yaml b/resources/units/ground_units/M1128 Stryker MGS.yaml deleted file mode 100644 index 3e33b602b..000000000 --- a/resources/units/ground_units/M1128 Stryker MGS.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: IFV -description: The M1128 Mobile Gun System is an eight-wheeled armored car of the Stryker - armored fighting vehicle family, mounting a 105 mm tank gun, based on the Canadian - LAV III light-armored vehicle manufactured by General Dynamics Land Systems. It - is in service with the United States Army but will be retired by the end of 2022. -introduced: 2006 -manufacturer: General Dynamics -origin: USA -price: 14 -role: Armoured Car -variants: - M1128 Stryker Mobile Gun System: {} -hit_points: 4 diff --git a/resources/units/ground_units/M1134 Stryker ATGM.yaml b/resources/units/ground_units/M1134 Stryker ATGM.yaml deleted file mode 100644 index 2dd44db0a..000000000 --- a/resources/units/ground_units/M1134 Stryker ATGM.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: ATGM -description: The ICV (Infantry Carrier Vehicle) Stryker is a family of eight-wheeled - armored fighting vehicles derived from the Canadian LAV III. -introduced: 2002 -manufacturer: General Dynamics -origin: USA -price: 12 -role: Armoured Car -variants: - M1134 Stryker ATGM (BGM-71 TOW): {} -hit_points: 4 diff --git a/resources/units/ground_units/M120.yaml b/resources/units/ground_units/M120.yaml deleted file mode 100644 index e88f123e5..000000000 --- a/resources/units/ground_units/M120.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 10 -variants: - MO 120 RT: null diff --git a/resources/units/ground_units/M12_GMC.yaml b/resources/units/ground_units/M12_GMC.yaml deleted file mode 100644 index 0a97b8c9a..000000000 --- a/resources/units/ground_units/M12_GMC.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Artillery -description: The 155 mm Gun Motor Carriage M12 was a U.S. self-propelled gun developed - during the Second World War. It mounted a 155 mm gun derived from the French Canon - de 155mm GPF field gun. -introduced: 1942 -manufacturer: Pressed Steel Car Company -origin: USA -price: 10 -role: Self-Propelled Gun -variants: - M12 Gun Motor Carriage: {} -hit_points: 15 diff --git a/resources/units/ground_units/M1_37mm.yaml b/resources/units/ground_units/M1_37mm.yaml deleted file mode 100644 index 7169165c4..000000000 --- a/resources/units/ground_units/M1_37mm.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: SHORAD -description: The 37 mm gun M1 was an anti-aircraft autocannon developed in the United - States. It was used by the US Army in World War II. In addition to the towed variant, - the gun was mounted, with two M2 machine guns, on the M2/M3 half-track, resulting - in the T28/T28E1/M15/M15A1 series of multiple gun motor carriages. In early World - War II, each Army Anti-Aircraft Artillery (AAA) Auto-Weapons battalion was authorized - a total of thirty-two 37 mm guns in its four firing batteries, plus other weapons. -introduced: 1939 -manufacturer: Colt -origin: USA -price: 7 -role: Anti-Aircraft Gun -variants: - M1 37mm Gun: {} -hit_points: 2 diff --git a/resources/units/ground_units/M2A1-105.yaml b/resources/units/ground_units/M2A1-105.yaml deleted file mode 100644 index 3552898ca..000000000 --- a/resources/units/ground_units/M2A1-105.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Artillery -description: -introduced: -manufacturer: -origin: -price: 10 -role: Field Howitzer -variants: - FH M2A1 105mm: {} -hit_points: 2 diff --git a/resources/units/ground_units/M2A1_halftrack.yaml b/resources/units/ground_units/M2A1_halftrack.yaml deleted file mode 100644 index ec8b719eb..000000000 --- a/resources/units/ground_units/M2A1_halftrack.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: APC -description: 'The M2 half-track car is an armored half-track produced by the United - States during World War II. ' -introduced: 1940 -manufacturer: White Motor Company -origin: USA -price: 4 -role: Armoured Personnel Carrier -variants: - M2A1 Half-Track: {} -hit_points: 7 diff --git a/resources/units/ground_units/M30_CC.yaml b/resources/units/ground_units/M30_CC.yaml deleted file mode 100644 index f81c7cb99..000000000 --- a/resources/units/ground_units/M30_CC.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Logistics -description: The M30 Cargo carrier was a variant of the M12 Gun Motor Carriage (a - US self-propelled gun), which itself was derived from the M3 Lee tank. Neither vehicle - was extensively produced, around hundreds being manufactured. It was exclusively - used in the Normandy theatre and followed the Allied push into Germany. It was judged - obsolete after the war and retired from service. -introduced: 1942 -manufacturer: Pressed Steel Car Company -origin: USA -price: 2 -role: Tracked Cargo Transporter -variants: - M30 Cargo Carrier: {} -hit_points: 15 diff --git a/resources/units/ground_units/M45_Quadmount.yaml b/resources/units/ground_units/M45_Quadmount.yaml deleted file mode 100644 index 26da34ada..000000000 --- a/resources/units/ground_units/M45_Quadmount.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: AAA -description: The M45 Quadmount (nicknamed the "meat chopper" and "Krautmower" for - its high rate of fire) was a weapon mounting consisting of four of the "HB", or - "heavy barrel" .50 caliber M2 Browning machine guns mounted in pairs on each side - of an open, electrically powered turret. It was developed by the W. L. Maxson Corporation - to replace the earlier M33 twin mount (also from Maxson). Although designed as an - anti-aircraft weapon, it was also used against ground targets. Introduced in 1943 - during World War II, it remained in US service as late as the Vietnam War. -introduced: 1943 -manufacturer: W. L. Maxson Corporation -origin: USA -price: 4 -role: Anti-Aircraft Gun -variants: - M45 Quadmount: {} -hit_points: 1 diff --git a/resources/units/ground_units/M48 Chaparral.yaml b/resources/units/ground_units/M48 Chaparral.yaml deleted file mode 100644 index 6e247553b..000000000 --- a/resources/units/ground_units/M48 Chaparral.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: SHORAD -description: The MIM-72A/M48 Chaparral is an American self-propelled surface-to-air - missile system based on the AIM-9 Sidewinder air-to-air missile system. The launcher - is based on the M113 family of vehicles. It entered service with the United States - Army in 1969 and was phased out between 1990 and 1998. -introduced: 1969 -manufacturer: Ford Motor Company -origin: USA -price: 16 -role: Self-Propelled Surface-to-Air Missile Launcher -variants: - M48 Chaparral: {} -hit_points: 2 diff --git a/resources/units/ground_units/M4A4_Sherman_FF.yaml b/resources/units/ground_units/M4A4_Sherman_FF.yaml deleted file mode 100644 index d194d064b..000000000 --- a/resources/units/ground_units/M4A4_Sherman_FF.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: ATGM -description: The Sherman Firefly was a tank used by the United Kingdom and some Commonwealth - and Allied armoured formations in the Second World War. It was based on the US M4 - Sherman, but fitted with the more powerful 3-inch (76.2 mm) calibre British 17-pounder - anti-tank gun as its main weapon. -introduced: 1943 -manufacturer: Chrysler -origin: USA/UK -price: 16 -role: Medium Tank -variants: - M4A4 Sherman Firefly: {} - Sherman Firefly VC: {} -hit_points: 15 diff --git a/resources/units/ground_units/M4_Sherman.yaml b/resources/units/ground_units/M4_Sherman.yaml deleted file mode 100644 index 0391f497a..000000000 --- a/resources/units/ground_units/M4_Sherman.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: Tank -description: The M4 Sherman, officially Medium Tank, M4, was the most widely used - medium tank by the United States and Western Allies in World War II. The M4 Sherman - proved to be reliable, relatively cheap to produce, and available in great numbers. - It was also the basis of several successful tank destroyers, such as the M10, 17pdr - SP Achilles and M36B1. Tens of thousands were distributed through the Lend-Lease - program to the British Commonwealth and Soviet Union. -introduced: 1942 -manufacturer: Fisher -origin: USA -price: 12 -role: Medium Tank -variants: - M4A2(75) Sherman: {} - Sherman III: {} -hit_points: 15 diff --git a/resources/units/ground_units/M4_Tractor.yaml b/resources/units/ground_units/M4_Tractor.yaml deleted file mode 100644 index ca6df5d2c..000000000 --- a/resources/units/ground_units/M4_Tractor.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Logistics -description: The M4 High-Speed Tractor was an artillery tractor used by the US Army - from 1943. -introduced: 1943 -manufacturer: Allis-Chalmers -origin: USA -price: 2 -role: Tracked Cargo Transporter -variants: - M4 High-Speed Tractor: {} -hit_points: 4 diff --git a/resources/units/ground_units/M6 Linebacker.yaml b/resources/units/ground_units/M6 Linebacker.yaml deleted file mode 100644 index 597b7993a..000000000 --- a/resources/units/ground_units/M6 Linebacker.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: SHORAD -description: The M6 Linebacker short-range air defense system was developed by Boeing - to meet the US Army requirements. The new vehicle was intended to counter the threat - posed by low-flying aircraft, helicopters, cruise missiles and unmanned aerial vehicles - to forward armored formations. Initial production Linebackers entered service with - the US Army in 1997. A total of 99 Bradley Linebackers were ordered, however in - 2006 these were phased-out of service. The M6 is an all-weather system, capable - of operating in day/night and all weather conditions. It is based on the M2 Bradley - IFV and is equipped with a quadruple launcher with FIM-92 Stinger short-range surface-to-air - missiles instead of the TOW ATGW. -introduced: 1997 -manufacturer: United Defense -origin: USA -price: 18 -role: Self-Propelled Anti-Aircraft System -variants: - M6 Linebacker: {} -hit_points: 6 diff --git a/resources/units/ground_units/M8_Greyhound.yaml b/resources/units/ground_units/M8_Greyhound.yaml deleted file mode 100644 index f5fdc3971..000000000 --- a/resources/units/ground_units/M8_Greyhound.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Recon -description: "The M8 Light Armored Car is a 6\xD76 armored car produced by the Ford\ - \ Motor Company during World War II. It was used from 1943 by United States and\ - \ British forces in Europe and the Pacific until the end of the war. The vehicle\ - \ was widely exported and as of 2006 still remained in service with some countries." -introduced: 1943 -manufacturer: Ford Motor Company -origin: USA -price: 8 -role: Light Armoured Car -variants: - M8 Greyhound Light Armored Car: {} -hit_points: 4 diff --git a/resources/units/ground_units/MCV-80.yaml b/resources/units/ground_units/MCV-80.yaml deleted file mode 100644 index 6297c5185..000000000 --- a/resources/units/ground_units/MCV-80.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: IFV -description: "The Warrior tracked vehicle family is a series of British armoured vehicles,\ - \ originally developed to replace the older FV430 series of armoured vehicles. The\ - \ Warrior started life as the MCV-80, \"Mechanised Combat Vehicle for the 1980s\"\ - . One of the requirements of the new vehicle was a top speed able to keep up with\ - \ the projected new MBT, the MBT-80 \u2013 later cancelled and replaced by what\ - \ became the Challenger 1 \u2013 which the then-current FV432 armoured personnel\ - \ carrier could not. " -introduced: 1984 -manufacturer: GKN Sankey -origin: UK -price: 10 -role: Infantry Fighting Vehicle -variants: - FV510 Warrior: {} -hit_points: 5 diff --git a/resources/units/ground_units/MLRS.yaml b/resources/units/ground_units/MLRS.yaml deleted file mode 100644 index 21c5667cf..000000000 --- a/resources/units/ground_units/MLRS.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Artillery -description: The M270 Multiple Launch Rocket System (M270 MLRS) is an armored, self-propelled, - multiple rocket launcher (a type of rocket artillery). Since the first M270s were - delivered to the U.S. Army in 1983, the MLRS has been adopted by several NATO countries. - Some 1,300 M270 systems have been manufactured in the United States and in Europe, - along with more than 700,000 rockets. The production of the M270 ended in 2003, - when a last batch was delivered to the Egyptian Army. -introduced: 1983 -manufacturer: Vought -origin: USA -price: 55 -role: Multiple-Launch Rocket System -variants: - M270 Multiple Launch Rocket System: {} -hit_points: 3 diff --git a/resources/units/ground_units/MTLB.yaml b/resources/units/ground_units/MTLB.yaml deleted file mode 100644 index 9b78fed3b..000000000 --- a/resources/units/ground_units/MTLB.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: APC -description: "The MT-LB (Russian: \u041C\u043D\u043E\u0433\u043E\u0446\u0435\u043B\ - \u0435\u0432\u043E\u0439 \u0422\u044F\u0433\u0430\u0447 \u041B\u0435\u0433\u043A\ - \u0438\u0439 \u0411\u0440\u043E\u043D\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\ - \u0439, romanized: Mnogotselevoy tyagach legky bronirovanny, literally \"multi-purpose\ - \ towing vehicle light armored\") is a Soviet multi-purpose fully amphibious auxiliary\ - \ armored tracked vehicle, which was introduced in the 1950s. It is also produced\ - \ in Poland, where (starting mid-1990s) its YaMZ engine was replaced by a Polish\ - \ version." -introduced: 1958 -manufacturer: Kharkiv -origin: USSR/Russia -price: 4 -role: Armoured Personnel Carrier -variants: - MT-LB: {} -hit_points: 3 diff --git a/resources/units/ground_units/Marder.yaml b/resources/units/ground_units/Marder.yaml deleted file mode 100644 index 7e88f45b1..000000000 --- a/resources/units/ground_units/Marder.yaml +++ /dev/null @@ -1,24 +0,0 @@ -class: IFV -description: The Marder (German for "marten") is a German infantry fighting vehicle - operated by the German Army as the main weapon of the Panzergrenadiere (mechanized - infantry) from the 1970s through to the present day. Developed as part of the rebuilding - of Germany's armoured fighting vehicle industry, the Marder has proven to be a successful - and solid infantry fighting vehicle design. While it used to include a few unique - features, such as a fully remote machine gun on the rear deck and gun ports on the - sides for infantry to fire through, these features have been deleted or streamlined - in later upgrade packages to bring it more in line with modern IFV design. Around - 2,100 were taken into service by the German Army in the early 1970s, but the vehicle - in its German variant was not sold to any foreign militaries. As the German Army - began to retire older vehicles, the Chilean government agreed to acquire 200 Marders; - the government of Greece has considered the purchase of 450 retired vehicles in - the past. Argentina uses a simplified and locally produced variant, the VCTP, and - has a number of vehicles based on that platform constructed by Henschel and built - by TAMSE. -introduced: 1988 -manufacturer: Rheinmetall Landsysteme -origin: Germany -price: 10 -role: Infantry Fighting Vehicle -variants: - Marder 1A3: {} -hit_points: 5 diff --git a/resources/units/ground_units/Maschinensatz_33.yaml b/resources/units/ground_units/Maschinensatz_33.yaml deleted file mode 100644 index 987c4dbec..000000000 --- a/resources/units/ground_units/Maschinensatz_33.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 10 -variants: - PU Maschinensatz_33: null -hit_points: 2 diff --git a/resources/units/ground_units/Merkava_Mk4.yaml b/resources/units/ground_units/Merkava_Mk4.yaml deleted file mode 100644 index b53c61aac..000000000 --- a/resources/units/ground_units/Merkava_Mk4.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Tank -description: 'The Merkava is a main battle tank used by the Israel Defense Forces. - The tank began development in 1970, and entered official service in 1979. Four main - variants of the tank have been deployed. It was first used extensively in the 1982 - Lebanon War. The name "Merkava" was derived from the IDF''s initial development - program name. Design criteria include rapid repair of battle damage, survivability, - cost-effectiveness and off-road performance. ' -introduced: 2004 -manufacturer: MANTAK -origin: Israel -price: 25 -role: Main Battle Tank -variants: - Merkava Mk IV: {} -hit_points: 20 diff --git a/resources/units/ground_units/NASAMS_Command_Post.yaml b/resources/units/ground_units/NASAMS_Command_Post.yaml deleted file mode 100644 index af60b32ce..000000000 --- a/resources/units/ground_units/NASAMS_Command_Post.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: CommandPost -price: 18 -description: "NASAMS (National/Norwegian Advanced Surface to Air Missile System) is a distributed and networked medium to long range air-defence system. - NASAMS was the first surface-based application for the AIM-120 AMRAAM (Advanced Medium Range Air-to-Air Missile)." -introduced: 1995 -manufacturer: Kongsberg Defence & Aerospace, Raytheon -origin: Norway, USA -variants: - SAM NASAMS C2: null -hit_points: 2 diff --git a/resources/units/ground_units/NASAMS_LN_B.yaml b/resources/units/ground_units/NASAMS_LN_B.yaml deleted file mode 100644 index 7165d0a83..000000000 --- a/resources/units/ground_units/NASAMS_LN_B.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Launcher -price: 15 -description: "NASAMS (National/Norwegian Advanced Surface to Air Missile System) is a distributed and networked medium to long range air-defence system. - NASAMS was the first surface-based application for the AIM-120 AMRAAM (Advanced Medium Range Air-to-Air Missile)." -introduced: 1995 -manufacturer: Kongsberg Defence & Aerospace, Raytheon -origin: Norway, USA -variants: - SAM NASAMS LN AIM-120B: null -hit_points: 2 diff --git a/resources/units/ground_units/NASAMS_LN_C.yaml b/resources/units/ground_units/NASAMS_LN_C.yaml deleted file mode 100644 index 0ffed7855..000000000 --- a/resources/units/ground_units/NASAMS_LN_C.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Launcher -price: 20 -description: "NASAMS (National/Norwegian Advanced Surface to Air Missile System) is a distributed and networked medium to long range air-defence system. - NASAMS was the first surface-based application for the AIM-120 AMRAAM (Advanced Medium Range Air-to-Air Missile)." -introduced: 1996 -manufacturer: Kongsberg Defence & Aerospace, Raytheon -origin: Norway, USA -variants: - SAM NASAMS LN AIM-120C: null -hit_points: 2 diff --git a/resources/units/ground_units/NASAMS_Radar_MPQ64F1.yaml b/resources/units/ground_units/NASAMS_Radar_MPQ64F1.yaml deleted file mode 100644 index 71f48cc15..000000000 --- a/resources/units/ground_units/NASAMS_Radar_MPQ64F1.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: SearchRadar -price: 26 -description: "NASAMS (National/Norwegian Advanced Surface to Air Missile System) is a distributed and networked medium to long range air-defence system. - NASAMS was the first surface-based application for the AIM-120 AMRAAM (Advanced Medium Range Air-to-Air Missile)." -introduced: 1995 -manufacturer: Kongsberg Defence & Aerospace, Raytheon -origin: Norway, USA -variants: - SAM NASAMS SR MPQ64F1: null -hit_points: 2 diff --git a/resources/units/ground_units/Osa 9A33 ln.yaml b/resources/units/ground_units/Osa 9A33 ln.yaml deleted file mode 100644 index ab8f5730d..000000000 --- a/resources/units/ground_units/Osa 9A33 ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SHORAD -price: 28 -variants: - SAM SA-8 Osa "Gecko" TEL: null -hit_points: 4 diff --git a/resources/units/ground_units/PLZ05.yaml b/resources/units/ground_units/PLZ05.yaml deleted file mode 100644 index 5064a0239..000000000 --- a/resources/units/ground_units/PLZ05.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Artillery -description: The PLZ-05 or the Type 05 is a 155 mm self-propelled howitzer developed - by the People's Liberation Army of China to replace the Type 59-1 130mm. The PLZ-05 - was officially unveiled at the Military Museum of the Chinese People's Revolution - to mark the 80th anniversary of the PLA in July 2007, and first entered service - with the PLA in 2008. -introduced: 1999 -manufacturer: Norinco -origin: China -price: 25 -role: Self propelled artillery -variants: - PLZ-05: {} -hit_points: 4 diff --git a/resources/units/ground_units/PT_76.yaml b/resources/units/ground_units/PT_76.yaml deleted file mode 100644 index d95e61040..000000000 --- a/resources/units/ground_units/PT_76.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: Recon -description: "The BRDM-2 (Boyevaya Razvedyvatelnaya Dozornaya Mashina, \u0411\u043E\ - \u0435\u0432\u0430\u044F \u0420\u0430\u0437\u0432\u0435\u0434\u044B\u0432\u0430\u0442\ - \u0435\u043B\u044C\u043D\u0430\u044F \u0414\u043E\u0437\u043E\u0440\u043D\u0430\u044F\ - \ \u041C\u0430\u0448\u0438\u043D\u0430, literally \"Combat Reconnaissance/Patrol\ - \ Vehicle\") is an amphibious armoured patrol car used by Russia and the former\ - \ Soviet Union. It was also known under the designations BTR-40PB, BTR-40P-2 and\ - \ GAZ 41-08. This vehicle, like many other Soviet designs, has been exported extensively\ - \ and is in use in at least 38 countries." -introduced: 1951 -manufacturer: VTZ, Kirov Factory -origin: USSR/Russia -price: 9 -role: Recon light tank -variants: - PT-76: {} -hit_points: 5 diff --git a/resources/units/ground_units/Pak40.yaml b/resources/units/ground_units/Pak40.yaml deleted file mode 100644 index 956db2f3f..000000000 --- a/resources/units/ground_units/Pak40.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Artillery -description: -introduced: -manufacturer: -origin: -price: 5 -role: Field Howitzer -variants: - FH Pak 40 75mm: {} -hit_points: 2 diff --git a/resources/units/ground_units/Paratrooper AKS-74.yaml b/resources/units/ground_units/Paratrooper AKS-74.yaml deleted file mode 100644 index a72ef68f5..000000000 --- a/resources/units/ground_units/Paratrooper AKS-74.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 5 -variants: - Paratrooper AKS: null -hit_points: 1 diff --git a/resources/units/ground_units/Paratrooper RPG-16.yaml b/resources/units/ground_units/Paratrooper RPG-16.yaml deleted file mode 100644 index 93e2e8d08..000000000 --- a/resources/units/ground_units/Paratrooper RPG-16.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 1 -variants: - Paratrooper RPG-16: null -hit_points: 1 diff --git a/resources/units/ground_units/Patriot AMG.yaml b/resources/units/ground_units/Patriot AMG.yaml deleted file mode 100644 index 8e9ec6c09..000000000 --- a/resources/units/ground_units/Patriot AMG.yaml +++ /dev/null @@ -1,4 +0,0 @@ -price: 35 -variants: - SAM Patriot CR (AMG AN/MRC-137): null -hit_points: 2 diff --git a/resources/units/ground_units/Patriot ECS.yaml b/resources/units/ground_units/Patriot ECS.yaml deleted file mode 100644 index 1679d95de..000000000 --- a/resources/units/ground_units/Patriot ECS.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 30 -variants: - SAM Patriot ECS: null -hit_points: 2 diff --git a/resources/units/ground_units/Patriot EPP.yaml b/resources/units/ground_units/Patriot EPP.yaml deleted file mode 100644 index 4bf6a946d..000000000 --- a/resources/units/ground_units/Patriot EPP.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Power -price: 15 -variants: - SAM Patriot EPP-III: null -hit_points: 2 diff --git a/resources/units/ground_units/Patriot cp.yaml b/resources/units/ground_units/Patriot cp.yaml deleted file mode 100644 index 1a4e3a24d..000000000 --- a/resources/units/ground_units/Patriot cp.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: CommandPost -price: 18 -variants: - SAM Patriot C2 ICC: null -hit_points: 2 diff --git a/resources/units/ground_units/Patriot ln.yaml b/resources/units/ground_units/Patriot ln.yaml deleted file mode 100644 index f8b04cd64..000000000 --- a/resources/units/ground_units/Patriot ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 15 -variants: - SAM Patriot LN: null -hit_points: 2 diff --git a/resources/units/ground_units/Patriot str.yaml b/resources/units/ground_units/Patriot str.yaml deleted file mode 100644 index eb515f570..000000000 --- a/resources/units/ground_units/Patriot str.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: SearchRadar -price: 22 -variants: - SAM Patriot STR: null -skynet_properties: # Override skynet default properties - can_engage_harm: true - # can_engage_air_weapon: true # https://github.com/walder/Skynet-IADS/tree/develop#engage-air-weapons - go_live_range_in_percent: 100 - harm_detection_chance: 90 - engagement_zone: SkynetIADSAbstractRadarElement.GO_LIVE_WHEN_IN_KILL_ZONE # https://github.com/walder/Skynet-IADS/tree/develop#engagement-zone - autonomous_behaviour: SkynetIADSAbstractRadarElement.AUTONOMOUS_STATE_DCS_AI # https://github.com/walder/Skynet-IADS/tree/develop#autonomous-mode-behaviour -hit_points: 2 diff --git a/resources/units/ground_units/Pz_IV_H.yaml b/resources/units/ground_units/Pz_IV_H.yaml deleted file mode 100644 index 58ec107f6..000000000 --- a/resources/units/ground_units/Pz_IV_H.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Tank -description: 'The Panzerkampfwagen IV (Pz.Kpfw. IV), commonly known as the Panzer - IV, was a German medium tank developed in the late 1930s and used extensively during - the Second World War. Its ordnance inventory designation was Sd.Kfz. 161. The Panzer - IV was the most numerous German tank and the second-most numerous German armored - fighting vehicle of the Second World War, with some 8,500 built. ' -introduced: 1943 -manufacturer: Krupp-Gruson/Vomag/Nibelungenwerke -origin: Germany -price: 16 -role: Medium Tank -variants: - Panzerkampfwagen IV Ausf. H: {} -hit_points: 15 diff --git a/resources/units/ground_units/Pz_V_Panther_G.yaml b/resources/units/ground_units/Pz_V_Panther_G.yaml deleted file mode 100644 index 86e55243e..000000000 --- a/resources/units/ground_units/Pz_V_Panther_G.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: Tank -description: The Panther is a German medium tank deployed during World War II on the - Eastern and Western Fronts in Europe from mid-1943 to the war's end in 1945. The - Panther was intended to counter the Soviet T-34 and to replace the Panzer III and - Panzer IV. Nevertheless, it served alongside the Panzer IV and the heavier Tiger - I until the end of the war. It is considered one of the best tanks of World War - II for its excellent firepower and protection, although its reliability was less - impressive. -introduced: 1944 -manufacturer: MAN/Daimler-Benz/MNH -origin: Germany -price: 24 -role: Medium Tank -variants: - Panzerkampfwagen V Panther Ausf. G: {} -hit_points: 15 diff --git a/resources/units/ground_units/QF_37_AA.yaml b/resources/units/ground_units/QF_37_AA.yaml deleted file mode 100644 index f33b9a499..000000000 --- a/resources/units/ground_units/QF_37_AA.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: SHORAD -description: The QF 3.7-inch AA was Britain's primary heavy anti-aircraft gun during - World War II. It was roughly the equivalent of the German 88 mm FlaK and American - 90 mm, but with a slightly larger calibre of 3.7 inches, approximately 94 mm. Production - began in 1937 and it was used throughout World War II in all theatres except the - Eastern Front. It remained in use after the war until AA guns were replaced by guided - missiles beginning in 1957. -introduced: 1937 -manufacturer: Vickers -origin: UK -price: 10 -role: Anti-Aircraft Gun -variants: - QF 3.7-inch AA Gun: {} -hit_points: 2 diff --git a/resources/units/ground_units/RLS_19J6.yaml b/resources/units/ground_units/RLS_19J6.yaml deleted file mode 100644 index 6fc8c4dff..000000000 --- a/resources/units/ground_units/RLS_19J6.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 16 -variants: - SAM SA-5 S-200 ST-68U "Tin Shield" SR: null -hit_points: 4 diff --git a/resources/units/ground_units/RPC_5N62V.yaml b/resources/units/ground_units/RPC_5N62V.yaml deleted file mode 100644 index 9b80d72aa..000000000 --- a/resources/units/ground_units/RPC_5N62V.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 18 -variants: - SAM SA-5 S-200 "Square Pair" TR": null -hit_points: 2 diff --git a/resources/units/ground_units/Roland ADS.yaml b/resources/units/ground_units/Roland ADS.yaml deleted file mode 100644 index 77643d78d..000000000 --- a/resources/units/ground_units/Roland ADS.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: SHORAD -description: 'he Roland is a Franco-German mobile short-range surface-to-air missile - (SAM) system. ' -introduced: 1981 -manufacturer: Euromissile -origin: France/Germany -price: 12 -role: Self-Propelled Surface-to-Air Missile Launcher -variants: - Roland 2 (Marder Chassis): {} -hit_points: 5 diff --git a/resources/units/ground_units/Roland Radar.yaml b/resources/units/ground_units/Roland Radar.yaml deleted file mode 100644 index bffe7105a..000000000 --- a/resources/units/ground_units/Roland Radar.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchTrackRadar -price: 16 -variants: - SAM Roland EWR: null -hit_points: 5 diff --git a/resources/units/ground_units/S-200_Launcher.yaml b/resources/units/ground_units/S-200_Launcher.yaml deleted file mode 100644 index a16ae7d05..000000000 --- a/resources/units/ground_units/S-200_Launcher.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 12 -variants: - SAM SA-5 S-200 "Gammon" LN": null -hit_points: 2 diff --git a/resources/units/ground_units/S-300PMU1 30N6E tr.yaml b/resources/units/ground_units/S-300PMU1 30N6E tr.yaml deleted file mode 100644 index ddabbf664..000000000 --- a/resources/units/ground_units/S-300PMU1 30N6E tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 32 -variants: - SAM SA-20 S-300PMU1 TR 30N6E(truck): null diff --git a/resources/units/ground_units/S-300PMU1 40B6M tr.yaml b/resources/units/ground_units/S-300PMU1 40B6M tr.yaml deleted file mode 100644 index 97385c238..000000000 --- a/resources/units/ground_units/S-300PMU1 40B6M tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 30 -variants: - SAM SA-20 S-300PMU1 TR 30N6E: null diff --git a/resources/units/ground_units/S-300PMU1 40B6MD sr.yaml b/resources/units/ground_units/S-300PMU1 40B6MD sr.yaml deleted file mode 100644 index 0f1461ec2..000000000 --- a/resources/units/ground_units/S-300PMU1 40B6MD sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SpecializedRadar -price: 38 -variants: - SAM SA-20 S-300PMU1 SR 5N66E: null diff --git a/resources/units/ground_units/S-300PMU1 54K6 cp.yaml b/resources/units/ground_units/S-300PMU1 54K6 cp.yaml deleted file mode 100644 index 25d0fb18e..000000000 --- a/resources/units/ground_units/S-300PMU1 54K6 cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 26 -variants: - SAM SA-20 S-300PMU1 CP 54K6: null diff --git a/resources/units/ground_units/S-300PMU1 5P85CE ln.yaml b/resources/units/ground_units/S-300PMU1 5P85CE ln.yaml deleted file mode 100644 index 3c797f36c..000000000 --- a/resources/units/ground_units/S-300PMU1 5P85CE ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 28 -variants: - SAM SA-20 S-300PMU1 LN 5P85CE: null diff --git a/resources/units/ground_units/S-300PMU1 5P85DE ln.yaml b/resources/units/ground_units/S-300PMU1 5P85DE ln.yaml deleted file mode 100644 index 9c16ad1ad..000000000 --- a/resources/units/ground_units/S-300PMU1 5P85DE ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 28 -variants: - SAM SA-20 S-300PMU1 LN 5P85DE: null diff --git a/resources/units/ground_units/S-300PMU1 64N6E sr.yaml b/resources/units/ground_units/S-300PMU1 64N6E sr.yaml deleted file mode 100644 index aa61830ae..000000000 --- a/resources/units/ground_units/S-300PMU1 64N6E sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 38 -variants: - SAM SA-20 S-300PMU1 SR 64N6E: null diff --git a/resources/units/ground_units/S-300PMU2 54K6E2 cp.yaml b/resources/units/ground_units/S-300PMU2 54K6E2 cp.yaml deleted file mode 100644 index 39d957ac6..000000000 --- a/resources/units/ground_units/S-300PMU2 54K6E2 cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 27 -variants: - SAM SA-20B S-300PMU2 CP 54K6E2: null diff --git a/resources/units/ground_units/S-300PMU2 5P85SE2 ln.yaml b/resources/units/ground_units/S-300PMU2 5P85SE2 ln.yaml deleted file mode 100644 index b069120cd..000000000 --- a/resources/units/ground_units/S-300PMU2 5P85SE2 ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 30 -variants: - SAM SA-20B S-300PMU2 LN 5P85SE2: null diff --git a/resources/units/ground_units/S-300PMU2 64H6E2 sr.yaml b/resources/units/ground_units/S-300PMU2 64H6E2 sr.yaml deleted file mode 100644 index 99e28d5b2..000000000 --- a/resources/units/ground_units/S-300PMU2 64H6E2 sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 40 -variants: - SAM SA-20B S-300PMU2 SR 64N6E2: null diff --git a/resources/units/ground_units/S-300PMU2 92H6E tr.yaml b/resources/units/ground_units/S-300PMU2 92H6E tr.yaml deleted file mode 100644 index 72904d1cf..000000000 --- a/resources/units/ground_units/S-300PMU2 92H6E tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 33 -variants: - SAM SA-20B S-300PMU2 TR 92H6E(truck): null diff --git a/resources/units/ground_units/S-300PS 30N6 TRAILER tr.yaml b/resources/units/ground_units/S-300PS 30N6 TRAILER tr.yaml deleted file mode 100644 index 474893f1e..000000000 --- a/resources/units/ground_units/S-300PS 30N6 TRAILER tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 26 -variants: - SAM SA-10B S-300PS 30N6 TR: null diff --git a/resources/units/ground_units/S-300PS 40B6M tr.yaml b/resources/units/ground_units/S-300PS 40B6M tr.yaml deleted file mode 100644 index a4f027591..000000000 --- a/resources/units/ground_units/S-300PS 40B6M tr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 24 -variants: - SAM SA-10 S-300 "Grumble" Flap Lid TR: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS 40B6MD sr.yaml b/resources/units/ground_units/S-300PS 40B6MD sr.yaml deleted file mode 100644 index b4f80617b..000000000 --- a/resources/units/ground_units/S-300PS 40B6MD sr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SpecializedRadar -price: 30 -variants: - SAM SA-10 S-300 "Grumble" Clam Shell SR: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS 54K6 cp.yaml b/resources/units/ground_units/S-300PS 54K6 cp.yaml deleted file mode 100644 index 6a1f53d3c..000000000 --- a/resources/units/ground_units/S-300PS 54K6 cp.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: CommandPost -price: 18 -variants: - SAM SA-10 S-300 "Grumble" C2: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS 5P85C ln.yaml b/resources/units/ground_units/S-300PS 5P85C ln.yaml deleted file mode 100644 index a33d76df0..000000000 --- a/resources/units/ground_units/S-300PS 5P85C ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 22 -variants: - SAM SA-10 S-300 "Grumble" TEL D: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS 5P85CE ln.yaml b/resources/units/ground_units/S-300PS 5P85CE ln.yaml deleted file mode 100644 index 5ea89faa8..000000000 --- a/resources/units/ground_units/S-300PS 5P85CE ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 24 -variants: - SAM SA-10 (5V55RUD) S-300PS LN 5P85CE: null diff --git a/resources/units/ground_units/S-300PS 5P85D ln.yaml b/resources/units/ground_units/S-300PS 5P85D ln.yaml deleted file mode 100644 index 2e4da42de..000000000 --- a/resources/units/ground_units/S-300PS 5P85D ln.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 22 -variants: - SAM SA-10 S-300 "Grumble" TEL C: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS 5P85DE ln.yaml b/resources/units/ground_units/S-300PS 5P85DE ln.yaml deleted file mode 100644 index 16105a1b9..000000000 --- a/resources/units/ground_units/S-300PS 5P85DE ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 24 -variants: - SAM SA-10 (5V55RUD) S-300PS LN 5P85DE: null diff --git a/resources/units/ground_units/S-300PS 5P85SE_mod ln.yaml b/resources/units/ground_units/S-300PS 5P85SE_mod ln.yaml deleted file mode 100644 index 8e8df7417..000000000 --- a/resources/units/ground_units/S-300PS 5P85SE_mod ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 24 -variants: - SAM SA-10B S-300PS 5P85SE LN: null diff --git a/resources/units/ground_units/S-300PS 5P85SU_mod ln.yaml b/resources/units/ground_units/S-300PS 5P85SU_mod ln.yaml deleted file mode 100644 index ed8839c96..000000000 --- a/resources/units/ground_units/S-300PS 5P85SU_mod ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 24 -variants: - SAM SA-10B S-300PS 5P85SU LN: null diff --git a/resources/units/ground_units/S-300PS 64H6E TRAILER sr.yaml b/resources/units/ground_units/S-300PS 64H6E TRAILER sr.yaml deleted file mode 100644 index eb77dcddd..000000000 --- a/resources/units/ground_units/S-300PS 64H6E TRAILER sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 32 -variants: - SAM SA-10B S-300PS 64H6E SR: null diff --git a/resources/units/ground_units/S-300PS 64H6E sr.yaml b/resources/units/ground_units/S-300PS 64H6E sr.yaml deleted file mode 100644 index 1c27d3aea..000000000 --- a/resources/units/ground_units/S-300PS 64H6E sr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 30 -variants: - SAM SA-10 S-300 "Grumble" Big Bird SR: null -hit_points: 4 diff --git a/resources/units/ground_units/S-300PS SA-10B 40B6M MAST tr.yaml b/resources/units/ground_units/S-300PS SA-10B 40B6M MAST tr.yaml deleted file mode 100644 index dddec7428..000000000 --- a/resources/units/ground_units/S-300PS SA-10B 40B6M MAST tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 26 -variants: - SAM SA-10B S-300PS 40B6M TR: null diff --git a/resources/units/ground_units/S-300PS SA-10B 40B6MD MAST sr.yaml b/resources/units/ground_units/S-300PS SA-10B 40B6MD MAST sr.yaml deleted file mode 100644 index 8ba86b33a..000000000 --- a/resources/units/ground_units/S-300PS SA-10B 40B6MD MAST sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SpecializedRadar -price: 32 -variants: - SAM SA-10B S-300PS 40B6MD SR: null diff --git a/resources/units/ground_units/S-300PS SA-10B 54K6 cp.yaml b/resources/units/ground_units/S-300PS SA-10B 54K6 cp.yaml deleted file mode 100644 index 19eb262d0..000000000 --- a/resources/units/ground_units/S-300PS SA-10B 54K6 cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 20 -variants: - SAM SA-10B S-300PS 54K6 CP: null diff --git a/resources/units/ground_units/S-300V 9A82 ln.yaml b/resources/units/ground_units/S-300V 9A82 ln.yaml deleted file mode 100644 index cb60d57b9..000000000 --- a/resources/units/ground_units/S-300V 9A82 ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 26 -variants: - SAM SA-12 S-300V 9A82 LN: null diff --git a/resources/units/ground_units/S-300V 9A83 ln.yaml b/resources/units/ground_units/S-300V 9A83 ln.yaml deleted file mode 100644 index b00cc7ee9..000000000 --- a/resources/units/ground_units/S-300V 9A83 ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 26 -variants: - SAM SA-12 S-300V 9A83 LN: null diff --git a/resources/units/ground_units/S-300V 9S15 sr.yaml b/resources/units/ground_units/S-300V 9S15 sr.yaml deleted file mode 100644 index 845c18158..000000000 --- a/resources/units/ground_units/S-300V 9S15 sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 34 -variants: - SAM SA-12 S-300V 9S15 SR: null diff --git a/resources/units/ground_units/S-300V 9S19 sr.yaml b/resources/units/ground_units/S-300V 9S19 sr.yaml deleted file mode 100644 index 4199c9178..000000000 --- a/resources/units/ground_units/S-300V 9S19 sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SpecializedRadar -price: 34 -variants: - SAM SA-12 S-300V 9S19 SR: null diff --git a/resources/units/ground_units/S-300V 9S32 tr.yaml b/resources/units/ground_units/S-300V 9S32 tr.yaml deleted file mode 100644 index 11e2dcb17..000000000 --- a/resources/units/ground_units/S-300V 9S32 tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 28 -variants: - SAM SA-12 S-300V 9S32 TR: null diff --git a/resources/units/ground_units/S-300V 9S457 cp.yaml b/resources/units/ground_units/S-300V 9S457 cp.yaml deleted file mode 100644 index 285c1dc91..000000000 --- a/resources/units/ground_units/S-300V 9S457 cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 22 -variants: - SAM SA-12 S-300V 9S457 CP: null diff --git a/resources/units/ground_units/S-300VM 9A82ME ln.yaml b/resources/units/ground_units/S-300VM 9A82ME ln.yaml deleted file mode 100644 index 71faef33c..000000000 --- a/resources/units/ground_units/S-300VM 9A82ME ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 32 -variants: - SAM SA-23 S-300VM 9A82ME LN: null diff --git a/resources/units/ground_units/S-300VM 9A83ME ln.yaml b/resources/units/ground_units/S-300VM 9A83ME ln.yaml deleted file mode 100644 index a00e27ca8..000000000 --- a/resources/units/ground_units/S-300VM 9A83ME ln.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 32 -variants: - SAM SA-23 S-300VM 9A83ME LN: null diff --git a/resources/units/ground_units/S-300VM 9S15M2 sr.yaml b/resources/units/ground_units/S-300VM 9S15M2 sr.yaml deleted file mode 100644 index 7cd2b2c06..000000000 --- a/resources/units/ground_units/S-300VM 9S15M2 sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SearchRadar -price: 45 -variants: - SAM SA-23 S-300VM 9S15M2 SR: null diff --git a/resources/units/ground_units/S-300VM 9S19M2 sr.yaml b/resources/units/ground_units/S-300VM 9S19M2 sr.yaml deleted file mode 100644 index 6bf864d28..000000000 --- a/resources/units/ground_units/S-300VM 9S19M2 sr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SpecializedRadar -price: 45 -variants: - SAM SA-23 S-300VM 9S19M2 SR: null diff --git a/resources/units/ground_units/S-300VM 9S32ME tr.yaml b/resources/units/ground_units/S-300VM 9S32ME tr.yaml deleted file mode 100644 index 1e580ef39..000000000 --- a/resources/units/ground_units/S-300VM 9S32ME tr.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: TrackRadar -price: 35 -variants: - SAM SA-23 S-300VM 9S32ME TR: null diff --git a/resources/units/ground_units/S-300VM 9S457ME cp.yaml b/resources/units/ground_units/S-300VM 9S457ME cp.yaml deleted file mode 100644 index 318e3554c..000000000 --- a/resources/units/ground_units/S-300VM 9S457ME cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 30 -variants: - SAM SA-23 S-300VM 9S457ME CP: null diff --git a/resources/units/ground_units/S-60_Type59_Artillery.yaml b/resources/units/ground_units/S-60_Type59_Artillery.yaml deleted file mode 100644 index 8a74f8edf..000000000 --- a/resources/units/ground_units/S-60_Type59_Artillery.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: AAA -description: "57 mm AZP S-60 (Russian: \u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\ - \u0447\u0435\u0441\u043A\u0430\u044F \u0437\u0435\u043D\u0438\u0442\u043D\u0430\u044F\ - \ \u043F\u0443\u0448\u043A\u0430 \u0421-60, abbrev. \u0410\u0417\u041F (AZP); literally:\ - \ Automatic anti-aircraft gun S-60) is a Soviet towed, road-transportable, short-\ - \ to medium-range, single-barrel anti-aircraft gun from the 1950s. The gun was extensively\ - \ used in Warsaw Pact, Middle Eastern and South-East Asian countries." -introduced: 1950 -manufacturer: TsAKB -origin: Soviet Union -price: 8 -role: Anti-Aircraft Gun/Anti-Tank Gun -variants: - S-60 57mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/SA-11 Buk CC 9S470M1.yaml b/resources/units/ground_units/SA-11 Buk CC 9S470M1.yaml deleted file mode 100644 index ccb63677f..000000000 --- a/resources/units/ground_units/SA-11 Buk CC 9S470M1.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: CommandPost -price: 25 -variants: - SAM SA-11 Buk "Gadfly" C2: null -hit_points: 4 diff --git a/resources/units/ground_units/SA-11 Buk LN 9A310M1.yaml b/resources/units/ground_units/SA-11 Buk LN 9A310M1.yaml deleted file mode 100644 index db7880d6c..000000000 --- a/resources/units/ground_units/SA-11 Buk LN 9A310M1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: TELAR -price: 30 -reversed_heading: true # Needs to be placed backwards! -variants: - SAM SA-11 Buk "Gadfly" Fire Dome TEL: null -hit_points: 4 diff --git a/resources/units/ground_units/SA-11 Buk SR 9S18M1.yaml b/resources/units/ground_units/SA-11 Buk SR 9S18M1.yaml deleted file mode 100644 index a84cacf80..000000000 --- a/resources/units/ground_units/SA-11 Buk SR 9S18M1.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 28 -variants: - SAM SA-11 Buk "Gadfly" Snow Drift SR: null -hit_points: 4 diff --git a/resources/units/ground_units/SA-14 Strela-3 manpad.yaml b/resources/units/ground_units/SA-14 Strela-3 manpad.yaml deleted file mode 100644 index 5eeb362b6..000000000 --- a/resources/units/ground_units/SA-14 Strela-3 manpad.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - SAM SA-14 Strela-3 manpad: null diff --git a/resources/units/ground_units/SA-17 Buk M1-2 LN 9A310M1-2.yaml b/resources/units/ground_units/SA-17 Buk M1-2 LN 9A310M1-2.yaml deleted file mode 100644 index e8d46a38a..000000000 --- a/resources/units/ground_units/SA-17 Buk M1-2 LN 9A310M1-2.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TELAR -price: 40 -reversed_heading: true # Needs to be placed backwards! -variants: - SAM SA-17 Buk M1-2 LN 9A310M1-2: null diff --git a/resources/units/ground_units/SA-18 Igla comm.yaml b/resources/units/ground_units/SA-18 Igla comm.yaml deleted file mode 100644 index e524e82c2..000000000 --- a/resources/units/ground_units/SA-18 Igla comm.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Infantry -price: 8 -variants: - MANPADS SA-18 Igla "Grouse" C2: null -hit_points: 1 diff --git a/resources/units/ground_units/SA-18 Igla manpad.yaml b/resources/units/ground_units/SA-18 Igla manpad.yaml deleted file mode 100644 index 6a20555c2..000000000 --- a/resources/units/ground_units/SA-18 Igla manpad.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - MANPADS SA-18 Igla "Grouse": null -hit_points: 1 diff --git a/resources/units/ground_units/SA-18 Igla-S comm.yaml b/resources/units/ground_units/SA-18 Igla-S comm.yaml deleted file mode 100644 index f400cc680..000000000 --- a/resources/units/ground_units/SA-18 Igla-S comm.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Infantry -price: 8 -variants: - MANPADS SA-18 Igla-S "Grouse" C2: null -hit_points: 1 diff --git a/resources/units/ground_units/SA-18 Igla-S manpad.yaml b/resources/units/ground_units/SA-18 Igla-S manpad.yaml deleted file mode 100644 index 5d64ba396..000000000 --- a/resources/units/ground_units/SA-18 Igla-S manpad.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - MANPADS SA-18 Igla-S "Grouse": null -hit_points: 1 diff --git a/resources/units/ground_units/SA-24 Igla-S manpad.yaml b/resources/units/ground_units/SA-24 Igla-S manpad.yaml deleted file mode 100644 index 16501992d..000000000 --- a/resources/units/ground_units/SA-24 Igla-S manpad.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - SAM SA-24 Igla-S manpad: null diff --git a/resources/units/ground_units/SA-8 Osa LD 9T217.yaml b/resources/units/ground_units/SA-8 Osa LD 9T217.yaml deleted file mode 100644 index fbb8b0487..000000000 --- a/resources/units/ground_units/SA-8 Osa LD 9T217.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Logistics -description: "The 9K33 Osa (Russian: 9\u041A33 \xAB\u041E\u0441\u0430\xBB, literally\ - \ \"wasp\"; NATO reporting name SA-8 Gecko) is a highly mobile, low-altitude, short-range\ - \ tactical surface-to-air missile system developed in the Soviet Union in the 1960s\ - \ and fielded in 1972. Its export version name is Romb." -introduced: 1981 -manufacturer: Ulyanovsk -origin: USSR/Russia -price: 3 -role: Self-Propelled Surface-to-Air Missile Launcher -variants: - SAM SA-8 Osa LD 9T217: {} diff --git a/resources/units/ground_units/SAU 2-C9.yaml b/resources/units/ground_units/SAU 2-C9.yaml deleted file mode 100644 index 9c3f61a1b..000000000 --- a/resources/units/ground_units/SAU 2-C9.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: Artillery -description: "The 2S9 NONA (\u041D\u043E\u0432\u0435\u0439\u0448\u0435\u0435 \u041E\ - \u0440\u0443\u0434\u0438\u0435 \u041D\u0430\u0437\u0435\u043C\u043D\u043E\u0439\ - \ \u0410\u0440\u0442\u0438\u043B\u0435\u0440\u0438\u0438 - Newest Ordnance of Ground\ - \ Artillery) is an extremely light-weight self-propelled and air-droppable 120 mm\ - \ gun-mortar designed in the Soviet Union, which entered service in 1981. The 2S9\ - \ chassis is designated the S-120 and based on the aluminium hull of the BTR-D airborne\ - \ multi-purpose tracked armoured personnel carrier. More generally, the 120 mm mortar\ - \ is referred to as the Nona, with the 2S9 also known as the Nona-S. Although no\ - \ figures have been released, it is estimated that well over 1,000 2S9 were built." -introduced: 1981 -manufacturer: Motovilikha -origin: USSR/Russia -price: 12 -role: Self-Propelled Mortar -variants: - 2S9 Nona-S: {} -hit_points: 4 diff --git a/resources/units/ground_units/SAU Akatsia.yaml b/resources/units/ground_units/SAU Akatsia.yaml deleted file mode 100644 index 37a0d693f..000000000 --- a/resources/units/ground_units/SAU Akatsia.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Artillery -description: "The SO-152 (Russian: \u0421\u041E-152) is a Soviet 152.4 mm self-propelled\ - \ gun developed in 1968. It was a response to the American 155 mm M109. " -introduced: 1971 -manufacturer: Uraltransmash -origin: USSR/Russia -price: 24 -role: Self-Propelled Gun -variants: - 2S3 Akatsiya: {} -hit_points: 4 diff --git a/resources/units/ground_units/SAU Gvozdika.yaml b/resources/units/ground_units/SAU Gvozdika.yaml deleted file mode 100644 index a6fdee8ef..000000000 --- a/resources/units/ground_units/SAU Gvozdika.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Artillery -description: "The 2S1 Gvozdika (Russian: 2\u04211 \xAB\u0413\u0432\u043E\u0437\u0434\ - \u0438\u043A\u0430\xBB, \"Carnation\") is a Soviet self-propelled howitzer based\ - \ on the MT-LBu multi-purpose chassis, mounting a 122 mm 2A18 howitzer. " -introduced: 1972 -manufacturer: Kharkiv -origin: USSR/Russia -price: 18 -role: Self-Propelled Gun -variants: - 2S1 Gvozdika: {} -hit_points: 4 diff --git a/resources/units/ground_units/SAU Msta.yaml b/resources/units/ground_units/SAU Msta.yaml deleted file mode 100644 index 2082d1cd0..000000000 --- a/resources/units/ground_units/SAU Msta.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Artillery -description: "The 2S19 \"Msta-S\" (Russian: \u041C\u0441\u0442\u0430, after the Msta\ - \ River) is a 152.4 mm self-propelled howitzer designed by Soviet Union, which entered\ - \ service in 1989 as the successor to the 2S3 Akatsiya. The vehicle is based on\ - \ the T-80 tank hull, but is powered by the T-72's diesel engine." -introduced: 1989 -manufacturer: Uraltransmash -origin: USSR/Russia -price: 30 -role: Self-Propelled Gun -variants: - 2S19 Msta-S: {} -hit_points: 4 diff --git a/resources/units/ground_units/SEPAR.yaml b/resources/units/ground_units/SEPAR.yaml deleted file mode 100644 index 230afbd65..000000000 --- a/resources/units/ground_units/SEPAR.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Recon -description: The AMX-10 RC is a reconnaissance vehicle built by GIAT. Over 240 are - in service in the French Army. In addition, 108 vehicles were sold to Morocco and - 12 to Qatar. RC stands for Roues-Canon, or wheeled gun. -introduced: 1970 -manufacturer: GIAT Industries -origin: France -price: 12 -role: Recon Vehicle -variants: - "AMX-10RCR SEPAR": {} diff --git a/resources/units/ground_units/SK_C_28_naval_gun.yaml b/resources/units/ground_units/SK_C_28_naval_gun.yaml deleted file mode 100644 index 4aa698a96..000000000 --- a/resources/units/ground_units/SK_C_28_naval_gun.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 0 -variants: - Gun 15cm SK C/28 Naval in Bunker: null -hit_points: 160 diff --git a/resources/units/ground_units/SNR_75V.yaml b/resources/units/ground_units/SNR_75V.yaml deleted file mode 100644 index 78b31623d..000000000 --- a/resources/units/ground_units/SNR_75V.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 12 -variants: - SAM SA-2 S-75 "Fan Song" TR: null -hit_points: 2 diff --git a/resources/units/ground_units/S_75M_Volhov.yaml b/resources/units/ground_units/S_75M_Volhov.yaml deleted file mode 100644 index 9fee7740d..000000000 --- a/resources/units/ground_units/S_75M_Volhov.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 8 -variants: - SAM SA-2 S-75 "Guideline" LN: null -hit_points: 2 diff --git a/resources/units/ground_units/S_75M_Volhov_V759.yaml b/resources/units/ground_units/S_75M_Volhov_V759.yaml deleted file mode 100644 index f6996b160..000000000 --- a/resources/units/ground_units/S_75M_Volhov_V759.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Launcher -price: 8 -variants: - SAM SA-2 (V759) LN SM-90: null diff --git a/resources/units/ground_units/Scud_B.yaml b/resources/units/ground_units/Scud_B.yaml deleted file mode 100644 index 54a05ce15..000000000 --- a/resources/units/ground_units/Scud_B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Missile -price: 0 -variants: - SSM SS-1C Scud-B: null -hit_points: 4 diff --git a/resources/units/ground_units/Sd_Kfz_2.yaml b/resources/units/ground_units/Sd_Kfz_2.yaml deleted file mode 100644 index 2718d8a08..000000000 --- a/resources/units/ground_units/Sd_Kfz_2.yaml +++ /dev/null @@ -1,4 +0,0 @@ -price: 1 -variants: - LUV Kettenrad: null -hit_points: 4 diff --git a/resources/units/ground_units/Sd_Kfz_234_2_Puma.yaml b/resources/units/ground_units/Sd_Kfz_234_2_Puma.yaml deleted file mode 100644 index a0c0fe603..000000000 --- a/resources/units/ground_units/Sd_Kfz_234_2_Puma.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Recon -description: - The Sd.Kfz. 234 (Sonderkraftfahrzeug 234, Special Purpose Vehicle 234), was a - family of armoured cars designed and built in Germany during World War II. The - vehicles were lightly armoured, armed with a 20, 50 or 75 mm main gun, and - powered by a Tatra V12 diesel engine. -introduced: 1943 -manufacturer: "Tatra/Büssing/Daimler-Benz/Schichau" -origin: Germany -price: 8 -role: Recon Vehicle -variants: - Sd.Kfz.234/2 Puma: {} -hit_points: 8 diff --git a/resources/units/ground_units/Sd_Kfz_251.yaml b/resources/units/ground_units/Sd_Kfz_251.yaml deleted file mode 100644 index c860e605f..000000000 --- a/resources/units/ground_units/Sd_Kfz_251.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: APC -description: The Sd.Kfz. 251 (Sonderkraftfahrzeug 251) half-track was a World War - II German armored personnel carrier designed by the Hanomag company, based on its - earlier, unarmored Sd.Kfz. 11 vehicle. The Sd.Kfz. 251 was designed to transport - the Panzergrenadier (German mechanized infantry) into battle. Sd.Kfz. 251s were - the most widely produced German half-tracks of the war, with at least 15,252 vehicles - and variants produced by seven manufacturers. -introduced: 1939 -manufacturer: Hanomag -origin: Germany -price: 4 -role: Armoured Personnel Carrier -variants: - Sd.Kfz.251 "Hanomag": {} -hit_points: 7 diff --git a/resources/units/ground_units/Sd_Kfz_7.yaml b/resources/units/ground_units/Sd_Kfz_7.yaml deleted file mode 100644 index 3daedcbb0..000000000 --- a/resources/units/ground_units/Sd_Kfz_7.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Logistics -description: The Carrier Sd.Kfz.7 Tractor was a Artillery tow truck. -introduced: 1938 -manufacturer: Kraus Maffei -origin: Germany -price: 1 -role: Tracked Cargo Transporter -variants: - Sd.Kfz.7 Tractor: {} -hit_points: 6 diff --git a/resources/units/ground_units/Silkworm_SR.yaml b/resources/units/ground_units/Silkworm_SR.yaml deleted file mode 100644 index f98e2d018..000000000 --- a/resources/units/ground_units/Silkworm_SR.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 0 -variants: - AShM Silkworm SR: null -hit_points: 4 diff --git a/resources/units/ground_units/Smerch.yaml b/resources/units/ground_units/Smerch.yaml deleted file mode 100644 index 2a91d7d58..000000000 --- a/resources/units/ground_units/Smerch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Artillery -description: "The BM-30 Smerch (Russian: \u0421\u043C\u0435\u0440\u0447, \"tornado\"\ - , \"whirlwind\"), 9K58 Smerch or 9A52-2 Smerch-M is a Soviet heavy multiple rocket\ - \ launcher. The system is intended to defeat personnel, armored, and soft targets\ - \ in concentration areas, artillery batteries, command posts and ammunition depots." -introduced: 1989 -manufacturer: Splav -origin: USSR/Russia -price: 60 -role: Multiple-Launch Rocket System -variants: - BM-30 Smerch (9M55K Cluster Rockets): {} -hit_points: 4 diff --git a/resources/units/ground_units/Smerch_HE.yaml b/resources/units/ground_units/Smerch_HE.yaml deleted file mode 100644 index 1bba5360a..000000000 --- a/resources/units/ground_units/Smerch_HE.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Artillery -description: "The BM-30 Smerch (Russian: \u0421\u043C\u0435\u0440\u0447, \"tornado\"\ - , \"whirlwind\"), 9K58 Smerch or 9A52-2 Smerch-M is a Soviet heavy multiple rocket\ - \ launcher. The system is intended to defeat personnel, armored, and soft targets\ - \ in concentration areas, artillery batteries, command posts and ammunition depots." -introduced: 1989 -manufacturer: Splav -origin: USSR/Russia -price: 40 -role: Multiple-Launch Rocket System -variants: - BM-30 Smerch (9M55K5 HE Rockets): {} -hit_points: 4 diff --git a/resources/units/ground_units/Soldier AK.yaml b/resources/units/ground_units/Soldier AK.yaml deleted file mode 100644 index 7c2c1e7ed..000000000 --- a/resources/units/ground_units/Soldier AK.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 5 -variants: - Infantry AK-74: null -hit_points: 1 diff --git a/resources/units/ground_units/Soldier M249.yaml b/resources/units/ground_units/Soldier M249.yaml deleted file mode 100644 index 4228d26c5..000000000 --- a/resources/units/ground_units/Soldier M249.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 1 -variants: - Infantry M249: null -hit_points: 1 diff --git a/resources/units/ground_units/Soldier M4 GRG.yaml b/resources/units/ground_units/Soldier M4 GRG.yaml deleted file mode 100644 index 36f600047..000000000 --- a/resources/units/ground_units/Soldier M4 GRG.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 4 -variants: - Infantry M4 Georgia: null -hit_points: 1 diff --git a/resources/units/ground_units/Soldier M4.yaml b/resources/units/ground_units/Soldier M4.yaml deleted file mode 100644 index 35f73d37e..000000000 --- a/resources/units/ground_units/Soldier M4.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 5 -variants: - Infantry M4: null -hit_points: 1 diff --git a/resources/units/ground_units/Soldier RPG.yaml b/resources/units/ground_units/Soldier RPG.yaml deleted file mode 100644 index 38388c877..000000000 --- a/resources/units/ground_units/Soldier RPG.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 1 -variants: - Infantry RPG: null -hit_points: 1 diff --git a/resources/units/ground_units/Soldier stinger.yaml b/resources/units/ground_units/Soldier stinger.yaml deleted file mode 100644 index 9a47acd18..000000000 --- a/resources/units/ground_units/Soldier stinger.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Manpad -spawn_weight: 1 -price: 0 -variants: - MANPADS Stinger: null -hit_points: 1 diff --git a/resources/units/ground_units/SpGH_Dana.yaml b/resources/units/ground_units/SpGH_Dana.yaml deleted file mode 100644 index b4a7d200c..000000000 --- a/resources/units/ground_units/SpGH_Dana.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Artillery -description: "The DANA (the name being derived from \"d\u011Blo automobiln\xED nab\xED\ - jen\xE9 automaticky\" (gun on truck loaded automatically)) is a wheeled self-propelled\ - \ artillery piece." -introduced: 1980 -manufacturer: ZTS -origin: Czechoslovakia -price: 26 -role: Self-Propelled Gun -variants: - SpGH DANA: {} -hit_points: 3 diff --git a/resources/units/ground_units/Stinger comm dsr.yaml b/resources/units/ground_units/Stinger comm dsr.yaml deleted file mode 100644 index 0ac8b1b2e..000000000 --- a/resources/units/ground_units/Stinger comm dsr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Infantry -price: 4 -variants: - MANPADS Stinger C2 Desert: null -hit_points: 1 diff --git a/resources/units/ground_units/Stinger comm.yaml b/resources/units/ground_units/Stinger comm.yaml deleted file mode 100644 index afc0927f9..000000000 --- a/resources/units/ground_units/Stinger comm.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Infantry -price: 4 -variants: - MANPADS Stinger C2: null -hit_points: 1 diff --git a/resources/units/ground_units/Strela-1 9P31.yaml b/resources/units/ground_units/Strela-1 9P31.yaml deleted file mode 100644 index 488afad11..000000000 --- a/resources/units/ground_units/Strela-1 9P31.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: SHORAD -description: "The 9K31 Strela-1 (Russian: 9\u041A31 \xAB\u0421\u0442\u0440\u0435\u043B\ - \u0430-1\xBB; English: arrow) is a highly mobile, short-range, low altitude infra-red\ - \ guided surface-to-air missile system. Originally developed by the Soviet Union\ - \ under the GRAU designation 9K31, it is commonly known by its NATO reporting name,\ - \ SA-9 \"Gaskin\". The system consists of a BRDM-2 amphibious vehicle, mounting\ - \ two pairs of ready-to-fire 9M31 missiles." -introduced: 1966 -manufacturer: Soviet state factories -origin: USSR/Russia -price: 12 -role: Self-Propelled Anti-Aircraft System -variants: - SA-9 Strela: {} -hit_points: 3 diff --git a/resources/units/ground_units/Strela-10M3.yaml b/resources/units/ground_units/Strela-10M3.yaml deleted file mode 100644 index f19b922c2..000000000 --- a/resources/units/ground_units/Strela-10M3.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: SHORAD -description: "The 9K35 Strela-10 (Russian: 9\u041A35 \xAB\u0421\u0442\u0440\u0435\u043B\ - \u0430-10\xBB; English: arrow) is a highly mobile, short-range surface-to-air missile\ - \ system. It is visually aimed, and utilizes optical/infrared-guidance. The system\ - \ is primarily intended to engage low-altitude threats, such as helicopters. \"\ - 9K35\" is its GRAU designation; its NATO reporting name is SA-13 \"Gopher\"." -introduced: 1981 -manufacturer: Ulyanovsk -origin: USSR/Russia -price: 16 -role: Self-Propelled Surface-to-Air Missile Launcher -variants: - SA-13 Gopher (9K35 Strela-10M3): {} -hit_points: 3 diff --git a/resources/units/ground_units/Stug_III.yaml b/resources/units/ground_units/Stug_III.yaml deleted file mode 100644 index 9de58c22d..000000000 --- a/resources/units/ground_units/Stug_III.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: ATGM -description: - The Sturmgeschtz III (StuG III) assault gun was Germany's most-produced fully - tracked armoured fighting vehicle during World War II, and second-most - produced German armored combat vehicle of any type after the Sd.Kfz. 251 - half-track. It was built on a slightly modified Panzer III chassis, replacing - the turret with an armored, fixed superstructure mounting a more powerful gun. - Initially intended as a mobile assault gun for direct-fire support for - infantry, the StuG III was continually modified, and much like the later - Jagdpanzer vehicles, was employed as a tank destroyer. -introduced: 1942 -manufacturer: Alkett/MIAG -origin: Germany -price: 12 -role: Assault Gun/Tank Destroyer -variants: - "Sturmgeschütz III Ausf. G": {} -hit_points: 10 diff --git a/resources/units/ground_units/Stug_IV.yaml b/resources/units/ground_units/Stug_IV.yaml deleted file mode 100644 index e0c89ecf2..000000000 --- a/resources/units/ground_units/Stug_IV.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: ATGM -description: - The Sturmgeschütz IV (StuG IV) (Sd.Kfz. 167) was a German assault gun variant - of the Panzer IV used in the latter part of the Second World War. It was - identical in role and concept to the highly successful StuG III assault gun - variant of the Panzer III. Both StuG models were given an exclusively tank - destroyer role in German formations and tactical planning in the last two - years of the war, greatly augmenting the capability of the dwindling tank - force available to the German army on the Eastern and Western fronts. -introduced: 1943 -manufacturer: Krupp -origin: Germany -price: 14 -role: Assault Gun/Tank Destroyer -variants: - "Sturmgeschütz IV": {} -hit_points: 15 diff --git a/resources/units/ground_units/SturmPzIV.yaml b/resources/units/ground_units/SturmPzIV.yaml deleted file mode 100644 index 4bb5d13a7..000000000 --- a/resources/units/ground_units/SturmPzIV.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: Tank -description: - The Sturmpanzer (also known as Sturmpanzer 43 or Sd.Kfz. 166) was a German - armoured infantry support gun based on the Panzer IV chassis used in the - Second World War. It was used at the Battles of Kursk, Anzio, Normandy, and - was deployed in the Warsaw Uprising. It was known by the nickname Brummbär - ("grumpy bear") by Allied intelligence, a name which was not used by the - Germans. German soldiers nicknamed it the "Stupa", a contraction of the term - Sturmpanzer. Just over 300 vehicles were built and they were assigned to four - independent battalions. -introduced: 1943 -manufacturer: Vienna Arsenal -origin: Germany -price: 10 -role: Self-Propelled Gun -variants: - "Sturmpanzer IV Brummbär": {} -hit_points: 15 diff --git a/resources/units/ground_units/T-55.yaml b/resources/units/ground_units/T-55.yaml deleted file mode 100644 index 6d312fe86..000000000 --- a/resources/units/ground_units/T-55.yaml +++ /dev/null @@ -1,18 +0,0 @@ -class: Tank -description: The T-54/55 series was the most-produced tank in history. Estimated production - numbers for the series range from 86,000 to 100,000. They were replaced by the T-62, - T-64, T-72, T-80 and T-90 tanks in the Soviet and Russian armies, but remain in - use by up to 50 other armies worldwide, some having received sophisticated retrofitting. - During the Cold War, Soviet tanks never directly faced their NATO adversaries in - combat in Europe. However, the T-54/55's first appearance in the West around the - period of the 1950s (then the beginning of the Cold War) spurred the United Kingdom - to develop a new tank gun, the Royal Ordnance L7, and the United States to develop - the M60 Patton. -introduced: 1963 -manufacturer: Kharkiv/UralVagonZavod -origin: USSR/Russia -price: 18 -role: Main Battle Tank -variants: - T-55A: {} -hit_points: 18 diff --git a/resources/units/ground_units/T-72B.yaml b/resources/units/ground_units/T-72B.yaml deleted file mode 100644 index 4c9fbacfe..000000000 --- a/resources/units/ground_units/T-72B.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Tank -description: The T-72 is a family of Soviet/Russian main battle tanks that first entered - production in 1971. About 20,000 T-72 tanks have been built, and refurbishment has - enabled many to remain in service for decades. The T-72A version introduced in 1979 - is considered a second-generation main battle tank. It was widely exported and saw - service in 40 countries and in numerous conflicts. The T-72B3 version introduced - in 2010 is considered a third-generation main battle tank (MBT). -introduced: 1985 -manufacturer: UralVagonZavod -origin: USSR/Russia -price: 20 -role: Main Battle Tank -variants: - T-72B with Kontakt-1 ERA: {} -hit_points: 25 diff --git a/resources/units/ground_units/T-72B3.yaml b/resources/units/ground_units/T-72B3.yaml deleted file mode 100644 index 6949ef8f2..000000000 --- a/resources/units/ground_units/T-72B3.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: Tank -description: The T-72 is a family of Soviet/Russian main battle tanks that first entered - production in 1971. About 20,000 T-72 tanks have been built, and refurbishment has - enabled many to remain in service for decades. The T-72A version introduced in 1979 - is considered a second-generation main battle tank. It was widely exported and saw - service in 40 countries and in numerous conflicts. The T-72B3 version introduced - in 2010 is considered a third-generation main battle tank (MBT). -introduced: 2010 -manufacturer: UralVagonZavod -origin: USSR/Russia -price: 25 -role: Main Battle Tank -variants: - T-72B3 model 2011: {} -hit_points: 25 diff --git a/resources/units/ground_units/T-80UD.yaml b/resources/units/ground_units/T-80UD.yaml deleted file mode 100644 index 9e01f9d87..000000000 --- a/resources/units/ground_units/T-80UD.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: Tank -description: The T-80 is a main battle tank (MBT) designed and manufactured in the - Soviet Union. When it entered service in 1976, it was the second MBT in the world - to be equipped with a gas turbine engine after the Swedish Strv 103 and the first - to use it as a primary propulsion engine. The T-80U was last produced in a factory - in Omsk, Russia, while the T-80UD and further-developed T-84 continue to be produced - in Ukraine. The T-80 and its variants are in service in Belarus, Cyprus, Egypt, - Kazakhstan,[12] Pakistan, Russia, South Korea, and Ukraine. -introduced: 1985 -manufacturer: Omsk Transmash -origin: USSR/Russia -price: 25 -role: Main Battle Tank -variants: - T-80UD: {} -hit_points: 28 diff --git a/resources/units/ground_units/T-90.yaml b/resources/units/ground_units/T-90.yaml deleted file mode 100644 index ac2936963..000000000 --- a/resources/units/ground_units/T-90.yaml +++ /dev/null @@ -1,14 +0,0 @@ -class: Tank -description: 'The T-90 is a third-generation Russian main battle tank that entered - service in 1993. The tank is a modern variation of the T-72B and incorporates many - features found on the T-80U. Originally called the T-72BU, but later renamed to - T-90, it is an advanced tank in service with Russian Ground Forces and the Naval - Infantry. ' -introduced: 2004 -manufacturer: UralVagonZavod -origin: Russia -price: 30 -role: Main Battle Tank -variants: - T-90A: {} -hit_points: 30 diff --git a/resources/units/ground_units/T155_Firtina.yaml b/resources/units/ground_units/T155_Firtina.yaml deleted file mode 100644 index 4e2a01b97..000000000 --- a/resources/units/ground_units/T155_Firtina.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: Artillery -description: "T-155 F\u0131rt\u0131na (English: Storm) is a Turkish 155 mm self-propelled\ - \ howitzer." -introduced: 1998 -manufacturer: Turkey -origin: Turkey -price: 28 -role: Self-Propelled Gun -variants: - Firtina: {} -hit_points: 5 diff --git a/resources/units/ground_units/TPZ.yaml b/resources/units/ground_units/TPZ.yaml deleted file mode 100644 index 2960d382a..000000000 --- a/resources/units/ground_units/TPZ.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: APC -description: The TPz (Transportpanzer) Fuchs ("fox") is a German armoured personnel - carrier originally developed by Daimler-Benz but manufactured and further developed - by the now Rheinmetall MAN Military Vehicles (RMMV). Fuchs was the second wheeled - armoured vehicle to enter service with the Bundeswehr (West German Military) and - it can be used for tasks including troop transport, engineer transport, bomb disposal, - Nuclear, Biological and Chemical reconnaissance and electronic warfare. RMMV and - its predecessors manufactured 1,236 Fuchs 1, mostly for the German Army. -introduced: 1979 -manufacturer: Rheinstahl Wehrtechnik -origin: Germany -price: 5 -role: Armoured Personnel Carrier -variants: - TPz Fuchs: {} -hit_points: 3 diff --git a/resources/units/ground_units/TRM2000.yaml b/resources/units/ground_units/TRM2000.yaml deleted file mode 100644 index 1d0b204d0..000000000 --- a/resources/units/ground_units/TRM2000.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 4 -variants: - TRM-2000: null diff --git a/resources/units/ground_units/TRM2000_AA20.yaml b/resources/units/ground_units/TRM2000_AA20.yaml deleted file mode 100644 index 82b4153e7..000000000 --- a/resources/units/ground_units/TRM2000_AA20.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: SHORAD -price: 8 -variants: - TRM-2000 53T2: {} diff --git a/resources/units/ground_units/TRM2000_Citerne.yaml b/resources/units/ground_units/TRM2000_Citerne.yaml deleted file mode 100644 index c4408fed2..000000000 --- a/resources/units/ground_units/TRM2000_Citerne.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 4 -variants: - TRM-2000 Fuel: null diff --git a/resources/units/ground_units/TRMMISTRAL.yaml b/resources/units/ground_units/TRMMISTRAL.yaml deleted file mode 100644 index 877b00a39..000000000 --- a/resources/units/ground_units/TRMMISTRAL.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: SHORAD -description: Mistral Missile on a Truck. -introduced: 1993 -manufacturer: GIAT Industries -origin: France -price: 14 -role: Shorad -variants: - Pamela: {} diff --git a/resources/units/ground_units/TYPE-59.yaml b/resources/units/ground_units/TYPE-59.yaml deleted file mode 100644 index 0c5f386cf..000000000 --- a/resources/units/ground_units/TYPE-59.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Tank -description: Type 59 -introduced: -manufacturer: -origin: China -price: 15 -role: Main Battle Tank -variants: - MT Type 59: {} -hit_points: 18 diff --git a/resources/units/ground_units/Tetrarch.yaml b/resources/units/ground_units/Tetrarch.yaml deleted file mode 100644 index faed876cc..000000000 --- a/resources/units/ground_units/Tetrarch.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Recon -description: The Light Tank Mk VII (A17), also known as the Tetrarch, was a British - light tank produced by Vickers-Armstrongs in the late 1930s and used during the - Second World War. The Tetrarch was the latest in the line of light tanks built by - the company for the British Army. They where declered obsolete in 1946. -introduced: 1938 -manufacturer: Vickers-Armstrongs -origin: UK -price: 8 -role: Airborne Light Tank -variants: - A17 Light Tank Mk VII Tetrarch: {} -hit_points: 4 diff --git a/resources/units/ground_units/Tiger_I.yaml b/resources/units/ground_units/Tiger_I.yaml deleted file mode 100644 index b9b403ec0..000000000 --- a/resources/units/ground_units/Tiger_I.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: Tank -description: The Tiger I was a German heavy tank of World War II that operated beginning - in 1942 in Africa and in the Soviet Union, usually in independent heavy tank battalions. - It was designated Panzerkampfwagen VI Ausf H during development but was changed - to Panzerkampfwagen VI Ausf E during production. The Tiger I gave the German Army - its first armoured fighting vehicle that mounted the 8.8 cm KwK 36 gun (derived - from the 8.8 cm Flak 36). 1,347 were built between August 1942 and August 1944. - After August 1944, production of the Tiger I was phased out in favour of the Tiger - II. 1347 have been build. -introduced: 1942 -manufacturer: Henschel -origin: Germany -price: 24 -role: Heavy Tank -variants: - Panzerkampfwagen VI Tiger Ausf. E: {} -hit_points: 20 diff --git a/resources/units/ground_units/Tiger_II_H.yaml b/resources/units/ground_units/Tiger_II_H.yaml deleted file mode 100644 index 33c3c543e..000000000 --- a/resources/units/ground_units/Tiger_II_H.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The Tiger II was the successor to the Tiger I, combining the latter's - thick armour with the armour sloping used on the Panther medium tank. The tank weighed - almost 70 tonnes, and was protected by 100 to 185 mm (3.9 to 7.3 in) of armour to - the front.It was armed with the long barrelled 8.8 cm KwK 43 L/71 anti-tank cannon. - The chassis was also the basis for the Jagdtiger turretless Jagdpanzer anti-tank - vehicle. The Tiger II was issued to heavy tank battalions of the Army and the Waffen-SS. - It was first used in combat by 503rd Heavy Panzer Battalion during the Allied invasion - of Normandy on 11 July 1944; on the Eastern Front, the first unit to be outfitted - with the Tiger II was the 501st Heavy Panzer Battalion, which by 1 September 1944 - listed 25 Tiger IIs operational. -introduced: 1944 -manufacturer: Henschel/Krupp -origin: Germany -price: 26 -role: Heavy Tank -variants: - Panzerkampfwagen Tiger Ausf. B Tiger II: {} -hit_points: 20 diff --git a/resources/units/ground_units/Tor 9A331.yaml b/resources/units/ground_units/Tor 9A331.yaml deleted file mode 100644 index fc36d1fb8..000000000 --- a/resources/units/ground_units/Tor 9A331.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: SHORAD -description: "The Tor missile system (Russian: \"\u0422\u043E\u0440\"; English: torus)\ - \ is an all-weather low to medium altitude, short-range surface-to-air missile system\ - \ designed for destroying airplanes, helicopters, cruise missiles, precision guided\ - \ munitions, unmanned aerial vehicles and short-range ballistic threats (anti-munitions)." -introduced: 1971 -manufacturer: Znamya Truda Plant -origin: USSR/Russia -price: 40 -role: Self-Propelled Anti-Aircraft System -variants: - SA-15 Tor: {} -hit_points: 4 diff --git a/resources/units/ground_units/Toyota_bleu.yaml b/resources/units/ground_units/Toyota_bleu.yaml deleted file mode 100644 index c4d1afd14..000000000 --- a/resources/units/ground_units/Toyota_bleu.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: IFV -price: 2 -variants: - DIM' TOYOTA BLUE: null diff --git a/resources/units/ground_units/Toyota_desert.yaml b/resources/units/ground_units/Toyota_desert.yaml deleted file mode 100644 index 10888c54e..000000000 --- a/resources/units/ground_units/Toyota_desert.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: IFV -price: 2 -variants: - DIM' TOYOTA DESERT: null diff --git a/resources/units/ground_units/Toyota_vert.yaml b/resources/units/ground_units/Toyota_vert.yaml deleted file mode 100644 index 381e339ab..000000000 --- a/resources/units/ground_units/Toyota_vert.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: IFV -price: 2 -variants: - DIM' TOYOTA GREEN: null diff --git a/resources/units/ground_units/Tracma.yaml b/resources/units/ground_units/Tracma.yaml deleted file mode 100644 index bca41b82c..000000000 --- a/resources/units/ground_units/Tracma.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 2 -variants: - Tracma TD 1500: null diff --git a/resources/units/ground_units/UAZ-469.yaml b/resources/units/ground_units/UAZ-469.yaml deleted file mode 100644 index beb001fa7..000000000 --- a/resources/units/ground_units/UAZ-469.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 3 -variants: - LUV UAZ-469 Jeep: null -hit_points: 1 diff --git a/resources/units/ground_units/Uragan_BM-27.yaml b/resources/units/ground_units/Uragan_BM-27.yaml deleted file mode 100644 index eb28b38e1..000000000 --- a/resources/units/ground_units/Uragan_BM-27.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Artillery -description: "The BM-27 Uragan (Russian: \u0423\u0440\u0430\u0433\u0430\u043D, lit.\u2009\ - 'Hurricane'; GRAU index 9P140) is a self-propelled multiple rocket launcher system\ - \ designed in the Soviet Union." -introduced: 1975 -manufacturer: Splav -origin: USSR/Russia -price: 50 -role: Multiple-Launch Rocket System -variants: - BM-27 Uragan: {} -hit_points: 4 diff --git a/resources/units/ground_units/Ural-375 ZU-23 Insurgent.yaml b/resources/units/ground_units/Ural-375 ZU-23 Insurgent.yaml deleted file mode 100644 index 1ab782fbd..000000000 --- a/resources/units/ground_units/Ural-375 ZU-23 Insurgent.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. - This variant is mounted on the bed of an Ural-375 6x6 truck. -introduced: 1961 -manufacturer: KBP/Ural -origin: USSR/Russia -price: 7 -role: Self-Propelled Anti-Aircraft Gun -variants: - ZU-23 on Ural-375 Insurgent: {} -hit_points: 2 diff --git a/resources/units/ground_units/Ural-375 ZU-23.yaml b/resources/units/ground_units/Ural-375 ZU-23.yaml deleted file mode 100644 index 4f41e8a67..000000000 --- a/resources/units/ground_units/Ural-375 ZU-23.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. - This variant is mounted on the bed of an Ural-375 6x6 truck. -introduced: 1961 -manufacturer: KBP/Ural -origin: USSR/Russia -price: 7 -role: Self-Propelled Anti-Aircraft Gun -variants: - ZU-23 on Ural-375: {} -hit_points: 2 diff --git a/resources/units/ground_units/Ural-375.yaml b/resources/units/ground_units/Ural-375.yaml deleted file mode 100644 index d3b6179a5..000000000 --- a/resources/units/ground_units/Ural-375.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Logistics -price: 3 -variants: - Truck Ural-375: null -hit_points: 2 diff --git a/resources/units/ground_units/Ural-4320-31.yaml b/resources/units/ground_units/Ural-4320-31.yaml deleted file mode 100644 index 0adb12207..000000000 --- a/resources/units/ground_units/Ural-4320-31.yaml +++ /dev/null @@ -1,4 +0,0 @@ -price: 1 -variants: - Truck Ural-4320-31 Arm'd: null -hit_points: 3 diff --git a/resources/units/ground_units/Ural-4320T.yaml b/resources/units/ground_units/Ural-4320T.yaml deleted file mode 100644 index f62b3a81a..000000000 --- a/resources/units/ground_units/Ural-4320T.yaml +++ /dev/null @@ -1,4 +0,0 @@ -price: 1 -variants: - Truck Ural-4320T: null -hit_points: 2 diff --git a/resources/units/ground_units/VABH.yaml b/resources/units/ground_units/VABH.yaml deleted file mode 100644 index 48f70948a..000000000 --- a/resources/units/ground_units/VABH.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 8 -variants: - VAB MEDICAL: null diff --git a/resources/units/ground_units/VAB_50.yaml b/resources/units/ground_units/VAB_50.yaml deleted file mode 100644 index dcb0800d2..000000000 --- a/resources/units/ground_units/VAB_50.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 4 -variants: - VAB .50: null diff --git a/resources/units/ground_units/VAB_HOT.yaml b/resources/units/ground_units/VAB_HOT.yaml deleted file mode 100644 index 9fb72a2ba..000000000 --- a/resources/units/ground_units/VAB_HOT.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: ATGM -description: The VAB HOT Mephisto is a wheeled armoured vehicle personnel carrier - VAB fitted with anti-tank missile launcher turret. -introduced: 1990 -manufacturer: GIAT Industries -origin: France -price: 8 -role: ATGM Vehicle -variants: - VAB Mephisto Frenchpack: {} diff --git a/resources/units/ground_units/VAB_MORTIER.yaml b/resources/units/ground_units/VAB_MORTIER.yaml deleted file mode 100644 index a479fdaf9..000000000 --- a/resources/units/ground_units/VAB_MORTIER.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 10 -variants: - VAB MORTIER: null diff --git a/resources/units/ground_units/VAB_Mephisto.yaml b/resources/units/ground_units/VAB_Mephisto.yaml deleted file mode 100644 index 5955d7ee5..000000000 --- a/resources/units/ground_units/VAB_Mephisto.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: ATGM -description: The VAB HOT Mephisto is a wheeled armoured vehicle personnel carrier - VAB fitted with anti-tank missile launcher turret. -introduced: 1990 -manufacturer: GIAT Industries -origin: France -price: 12 -role: ATGM Vehicle -variants: - VAB Mephisto: {} -hit_points: 4 diff --git a/resources/units/ground_units/VAB_RADIO.yaml b/resources/units/ground_units/VAB_RADIO.yaml deleted file mode 100644 index 8f96fe1d1..000000000 --- a/resources/units/ground_units/VAB_RADIO.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 6 -variants: - VAB: null diff --git a/resources/units/ground_units/VBAE.yaml b/resources/units/ground_units/VBAE.yaml deleted file mode 100644 index f804297a6..000000000 --- a/resources/units/ground_units/VBAE.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 8 -variants: - VBAE CRAB: null diff --git a/resources/units/ground_units/VBAE_MMP.yaml b/resources/units/ground_units/VBAE_MMP.yaml deleted file mode 100644 index 304d23600..000000000 --- a/resources/units/ground_units/VBAE_MMP.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 12 -variants: - VBAE CRAB MMP: null diff --git a/resources/units/ground_units/VBCI.yaml b/resources/units/ground_units/VBCI.yaml deleted file mode 100644 index 54874564f..000000000 --- a/resources/units/ground_units/VBCI.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: IFV -description: "The Véhicule Blindé de Combat d'Infanterie (VBCI : Armoured vehicle for infantry combat) is a French Infantry fighting vehicle designed to replace the AMX-10P." -introduced: 2005 -manufacturer: Nexter Systems -origin: France -price: 14 -role: Infantry Fighting Vehicle -variants: - VBCI: {} diff --git a/resources/units/ground_units/VBL-Radio.yaml b/resources/units/ground_units/VBL-Radio.yaml deleted file mode 100644 index ce21a77e5..000000000 --- a/resources/units/ground_units/VBL-Radio.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 1 -variants: - VBL: null diff --git a/resources/units/ground_units/VBL50.yaml b/resources/units/ground_units/VBL50.yaml deleted file mode 100644 index 679f737d1..000000000 --- a/resources/units/ground_units/VBL50.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: Recon -description: The Panhard Véhicule Blindé Léger ("Light armoured vehicle"), also known by its acronym Panhard VBL or simply VBL, is a French wheeled 4x4 all-terrain vehicle built by Panhard. The vehicle is offered in various configurations, and was designed to combine the agility of the Peugeot P4 liaison vehicle with adequate protection against small arms fire, artillery fragments, mines and NBC weapons. Produced between 1985 and 2010, the vehicle has been used by the French Army and other European, African and Central American armies in various conflicts since the 1980s. This variant is equiped with .50 cal gun. -introduced: 1985 -manufacturer: Panhard -origin: France -price: 2 -role: Recon Vehicle -variants: - VBL .50: null diff --git a/resources/units/ground_units/VBLANF1.yaml b/resources/units/ground_units/VBLANF1.yaml deleted file mode 100644 index b36516ae1..000000000 --- a/resources/units/ground_units/VBLANF1.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: Recon -description: The Panhard Véhicule Blindé Léger ("Light armoured vehicle"), also known by its acronym Panhard VBL or simply VBL, is a French wheeled 4x4 all-terrain vehicle built by Panhard. The vehicle is offered in various configurations, and was designed to combine the agility of the Peugeot P4 liaison vehicle with adequate protection against small arms fire, artillery fragments, mines and NBC weapons. Produced between 1985 and 2010, the vehicle has been used by the French Army and other European, African and Central American armies in various conflicts since the 1980s. This variant is equiped with the AN/F1 machine gun. -introduced: 1985 -manufacturer: Panhard -origin: France -price: 2 -role: Recon Vehicle -variants: - VBL AANF1: null diff --git a/resources/units/ground_units/VIB_VBR.yaml b/resources/units/ground_units/VIB_VBR.yaml deleted file mode 100644 index 6da553035..000000000 --- a/resources/units/ground_units/VIB_VBR.yaml +++ /dev/null @@ -1,3 +0,0 @@ -price: 6 -variants: - VAB T20/13: null diff --git a/resources/units/ground_units/Vulcan.yaml b/resources/units/ground_units/Vulcan.yaml deleted file mode 100644 index 06d2bf3b0..000000000 --- a/resources/units/ground_units/Vulcan.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: AAA -description: "The M163 had a fairly limited range from the start. Its 20x102mm round\ - \ gave it a low effective range of only 1,200 meters, and its standard air-defense\ - \ load of HEI-T rounds would self-destruct at approximately 1800 meters, a hard\ - \ limit on range. Additionally, the radar was a range-only set incapable of finding\ - \ targets. In US and Israeli service, the VADS has rarely been needed in its intended\ - \ purpose of providing defense against aerial threats\u2014consequently, the Vulcan\ - \ gun system was in use throughout the late 1980s and early 1990s primarily as a\ - \ ground support weapon." -introduced: 1989 -manufacturer: General Electric -origin: USA -price: 10 -role: Self-Propelled Anti-Aircraft Gun -variants: - M163 Vulcan Air Defense System: {} -hit_points: 3 diff --git a/resources/units/ground_units/Wespe124.yaml b/resources/units/ground_units/Wespe124.yaml deleted file mode 100644 index 08246799c..000000000 --- a/resources/units/ground_units/Wespe124.yaml +++ /dev/null @@ -1,10 +0,0 @@ -class: Artillery -description: -introduced: -manufacturer: -origin: -price: 15 -role: Self Propelled Gun -variants: - SPH Sd.Kfz.124 Wespe 105mm: {} -hit_points: 4 diff --git a/resources/units/ground_units/Willys_MB.yaml b/resources/units/ground_units/Willys_MB.yaml deleted file mode 100644 index d1e7278dc..000000000 --- a/resources/units/ground_units/Willys_MB.yaml +++ /dev/null @@ -1,12 +0,0 @@ -class: Logistics -description: The jeep became the primary light wheeled transport vehicle of the United - States military and its allies, with President Eisenhower once calling it "one of - three decisive weapons the U.S. had during WWII." After WW2 it served in many conflicts. -introduced: 1997 -manufacturer: United Defense -origin: USA -price: 1 -role: Recon Vehicle -variants: - Willys Jeep: {} -hit_points: 2 diff --git a/resources/units/ground_units/ZBD04A.yaml b/resources/units/ground_units/ZBD04A.yaml deleted file mode 100644 index 42159c2d4..000000000 --- a/resources/units/ground_units/ZBD04A.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: IFV -description: The ZBD-04 or Type 04 (industrial designation WZ502) is a Chinese infantry - fighting vehicle. It bears some external resemblance to the BMP-3, particularly - with regards to its turret and main armament; however, the chassis and internal - subsystems possesses a different layout. -introduced: 1999 -manufacturer: Norinco -origin: China -price: 12 -role: Infantry Fighting Vehicle -variants: - Type 04A (ZBD-04A): {} -hit_points: 6 diff --git a/resources/units/ground_units/ZSU-23-4 Shilka.yaml b/resources/units/ground_units/ZSU-23-4 Shilka.yaml deleted file mode 100644 index d2b9a7cff..000000000 --- a/resources/units/ground_units/ZSU-23-4 Shilka.yaml +++ /dev/null @@ -1,11 +0,0 @@ -class: AAA -description: The ZSU-23-4 "Shilka" is a lightly armored Soviet self-propelled, radar - guided anti-aircraft weapon system (SPAAG). About 6500 have been build. -introduced: 1960 -manufacturer: MMZ -origin: USSR/Russia -price: 10 -role: Self-Propelled Anti-Aircraft Gun -variants: - ZSU-23-4 Shilka: {} -hit_points: 4 diff --git a/resources/units/ground_units/ZSU_57_2.yaml b/resources/units/ground_units/ZSU_57_2.yaml deleted file mode 100644 index 666e5ed94..000000000 --- a/resources/units/ground_units/ZSU_57_2.yaml +++ /dev/null @@ -1,16 +0,0 @@ -class: AAA -description: "The ZSU-57-2 Ob'yekt 500 is a Soviet self-propelled anti-aircraft gun\ - \ (SPAAG), armed with two 57 mm autocannons. 'ZSU' stands for Zenitnaya Samokhodnaya\ - \ Ustanovka (Russian: \u0417\u0435\u043D\u0438\u0442\u043D\u0430\u044F \u0421\u0430\ - \u043C\u043E\u0445\u043E\u0434\u043D\u0430\u044F \u0423\u0441\u0442\u0430\u043D\u043E\ - \u0432\u043A\u0430), meaning \"anti-aircraft self-propelled mount\", '57' stands\ - \ for the bore of the armament in millimetres and '2' stands for the number of gun\ - \ barrels. It was the first Soviet mass-produced tracked SPAAG." -introduced: 1955 -manufacturer: Omsk Works -origin: USSR/Russia -price: 12 -role: Self-Propelled Anti-Aircraft Gun -variants: - ZSU-57-2 'Sparka': {} -hit_points: 18 diff --git a/resources/units/ground_units/ZTZ96B.yaml b/resources/units/ground_units/ZTZ96B.yaml deleted file mode 100644 index cd79a551e..000000000 --- a/resources/units/ground_units/ZTZ96B.yaml +++ /dev/null @@ -1,13 +0,0 @@ -class: Tank -description: The Type 96 or ZTZ96 is a Chinese second generation main battle tank - (MBT). The final evolution of the Type 88 design, the Type 96 entered service with - the People's Liberation Army (PLA) in 1997. The later variants of the Type 96 are - regarded as near-equivalents to China's third generation MBT. -introduced: 1979 -manufacturer: First Inner Mongolia Machinery Factory -origin: China -price: 30 -role: Main Battle Tank -variants: - Type 96B (ZTZ-96B): {} -hit_points: 25 diff --git a/resources/units/ground_units/ZU-23 Closed Insurgent.yaml b/resources/units/ground_units/ZU-23 Closed Insurgent.yaml deleted file mode 100644 index 99d84760d..000000000 --- a/resources/units/ground_units/ZU-23 Closed Insurgent.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. - This variant is mounted on a closed emplacement. -price: 6 -variants: - AAA ZU-23 Insurgent Closed Emplacement: null -hit_points: 2 diff --git a/resources/units/ground_units/ZU-23 Emplacement Closed.yaml b/resources/units/ground_units/ZU-23 Emplacement Closed.yaml deleted file mode 100644 index 30354f0d5..000000000 --- a/resources/units/ground_units/ZU-23 Emplacement Closed.yaml +++ /dev/null @@ -1,9 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. - This variant is mounted on a closed emplacement. -price: 6 -variants: - AAA ZU-23 Closed Emplacement: null -hit_points: 2 diff --git a/resources/units/ground_units/ZU-23 Emplacement.yaml b/resources/units/ground_units/ZU-23 Emplacement.yaml deleted file mode 100644 index 363dfeb74..000000000 --- a/resources/units/ground_units/ZU-23 Emplacement.yaml +++ /dev/null @@ -1,8 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. -price: 6 -variants: - AAA ZU-23 Emplacement: null -hit_points: 1 diff --git a/resources/units/ground_units/ZU-23 Insurgent.yaml b/resources/units/ground_units/ZU-23 Insurgent.yaml deleted file mode 100644 index 776ca61e4..000000000 --- a/resources/units/ground_units/ZU-23 Insurgent.yaml +++ /dev/null @@ -1,8 +0,0 @@ -class: AAA -description: - The ZU-23-2 is a Soviet towed 23×152mm anti-aircraft twin-barreled - autocannon. ZU stands for Zenitnaya Ustanovka – anti-aircraft mount. -price: 6 -variants: - AAA ZU-23 Insurgent Emplacement: null -hit_points: 1 diff --git a/resources/units/ground_units/bofors40.yaml b/resources/units/ground_units/bofors40.yaml deleted file mode 100644 index 78318bfbc..000000000 --- a/resources/units/ground_units/bofors40.yaml +++ /dev/null @@ -1,17 +0,0 @@ -class: AAA -description: The Bofors 40 mm gun, often referred to simply as the Bofors gun, is - an anti-aircraft autocannon designed in the 1930s by the Swedish arms manufacturer - AB Bofors. It was one of the most popular medium-weight anti-aircraft systems during - World War II, used by most of the western Allies as well as some captured systems - being used by the Axis powers. A small number of these weapons remain in service - to this day, and saw action as late as the Persian Gulf War. -introduced: 1934 -manufacturer: Bofors -origin: Sweden -price: 8 -role: Anti-Aircraft Gun -variants: - Bofors 40 mm Gun: {} - QF 40 mm Mark III: - introduced: 1939 -hit_points: 1 diff --git a/resources/units/ground_units/flak18.yaml b/resources/units/ground_units/flak18.yaml deleted file mode 100644 index 1eb811d6f..000000000 --- a/resources/units/ground_units/flak18.yaml +++ /dev/null @@ -1,20 +0,0 @@ -class: AAA -description: - The 8.8 cm Flak 18/36/37/41 is a German 88 mm anti-aircraft and anti-tank - artillery gun, developed in the 1930s. It was widely used by Germany - throughout World War II and is one of the most recognized German weapons of - that conflict. Development of the original model led to a wide variety of - guns. Air defense units were usually deployed with either a Kommandogerät - ("command device") fire control computer or a portable Würzburg radar, which - were responsible for its high level of accuracy against aircraft. The - versatile carriage allowed the 8.8 cm Flak to be fired in a limited anti-tank - mode when still on its wheels; it could be completely emplaced in only two and - a half minutes. -introduced: 1936 -manufacturer: Krupp/Rheinmetall -origin: Germany -price: 6 -role: Anti-Aircraft Gun/Anti-Tank Gun -variants: - 8.8 cm Flak 18: {} -hit_points: 2 diff --git a/resources/units/ground_units/flak30.yaml b/resources/units/ground_units/flak30.yaml deleted file mode 100644 index b74e63a37..000000000 --- a/resources/units/ground_units/flak30.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: AAA -description: The Flak 38 (Flugzeugabwehrkanone 30) and improved Flak 38 were 20 mm - anti-aircraft guns used by various German forces throughout World War II. It was - not only the primary German light anti-aircraft gun, but by far the most numerously - produced German artillery piece throughout the war. It was produced in a variety - of models, notably the Flakvierling 38 which combined four Flak 38 autocannons onto - a single carriage. -introduced: 1934 -manufacturer: Mauser -origin: Germany -price: 6 -role: Anti-Aircraft Gun -variants: - 2 cm Flak 38: {} -hit_points: 1 diff --git a/resources/units/ground_units/flak36.yaml b/resources/units/ground_units/flak36.yaml deleted file mode 100644 index 3c89becff..000000000 --- a/resources/units/ground_units/flak36.yaml +++ /dev/null @@ -1,20 +0,0 @@ -class: AAA -description: - The 8.8 cm Flak 18/36/37/41 is a German 88 mm anti-aircraft and anti-tank - artillery gun, developed in the 1930s. It was widely used by Germany - throughout World War II and is one of the most recognized German weapons of - that conflict. Development of the original model led to a wide variety of - guns. Air defense units were usually deployed with either a Kommandogerät - ("command device") fire control computer or a portable Würzburg radar, which - were responsible for its high level of accuracy against aircraft. The - versatile carriage allowed the 8.8 cm Flak to be fired in a limited anti-tank - mode when still on its wheels; it could be completely emplaced in only two and - a half minutes. -introduced: 1936 -manufacturer: Krupp/Rheinmetall -origin: Germany -price: 8 -role: Anti-Aircraft Gun/Anti-Tank Gun -variants: - 8.8 cm Flak 36: {} -hit_points: 2 diff --git a/resources/units/ground_units/flak37.yaml b/resources/units/ground_units/flak37.yaml deleted file mode 100644 index 02df43710..000000000 --- a/resources/units/ground_units/flak37.yaml +++ /dev/null @@ -1,20 +0,0 @@ -class: AAA -description: - The 8.8 cm Flak 18/36/37/41 is a German 88 mm anti-aircraft and anti-tank - artillery gun, developed in the 1930s. It was widely used by Germany - throughout World War II and is one of the most recognized German weapons of - that conflict. Development of the original model led to a wide variety of - guns. Air defense units were usually deployed with either a Kommandogerät - ("command device") fire control computer or a portable Würzburg radar, which - were responsible for its high level of accuracy against aircraft. The - versatile carriage allowed the 8.8 cm Flak to be fired in a limited anti-tank - mode when still on its wheels; it could be completely emplaced in only two and - a half minutes. -introduced: 1936 -manufacturer: Krupp/Rheinmetall -origin: Germany -price: 9 -role: Anti-Aircraft Gun/Anti-Tank Gun -variants: - 8.8 cm Flak 37: {} -hit_points: 2 diff --git a/resources/units/ground_units/flak38.yaml b/resources/units/ground_units/flak38.yaml deleted file mode 100644 index 261a352fd..000000000 --- a/resources/units/ground_units/flak38.yaml +++ /dev/null @@ -1,15 +0,0 @@ -class: AAA -description: The Flak 30 (Flugzeugabwehrkanone 30) and improved Flak 38 were 20 mm - anti-aircraft guns used by various German forces throughout World War II. It was - not only the primary German light anti-aircraft gun, but by far the most numerously - produced German artillery piece throughout the war. It was produced in a variety - of models, notably the Flakvierling 38 which combined four Flak 38 autocannons onto - a single carriage. -introduced: 1934 -manufacturer: Mauser -origin: Germany -price: 5 -role: Anti-Aircraft Gun -variants: - 2 cm Flakvierling 38: {} -hit_points: 1 diff --git a/resources/units/ground_units/flak41.yaml b/resources/units/ground_units/flak41.yaml deleted file mode 100644 index 9ecbb0dbf..000000000 --- a/resources/units/ground_units/flak41.yaml +++ /dev/null @@ -1,20 +0,0 @@ -class: AAA -description: - The 8.8 cm Flak 18/36/37/41 is a German 88 mm anti-aircraft and anti-tank - artillery gun, developed in the 1930s. It was widely used by Germany - throughout World War II and is one of the most recognized German weapons of - that conflict. Development of the original model led to a wide variety of - guns. Air defense units were usually deployed with either a Kommandogerät - ("command device") fire control computer or a portable Würzburg radar, which - were responsible for its high level of accuracy against aircraft. The - versatile carriage allowed the 8.8 cm Flak to be fired in a limited anti-tank - mode when still on its wheels; it could be completely emplaced in only two and - a half minutes. -introduced: 1943 -manufacturer: Krupp/Rheinmetall -origin: Germany -price: 10 -role: Anti-Aircraft Gun/Anti-Tank Gun -variants: - 8.8 cm Flak 41: {} -hit_points: 2 diff --git a/resources/units/ground_units/house2arm.yaml b/resources/units/ground_units/house2arm.yaml deleted file mode 100644 index 2fe121fff..000000000 --- a/resources/units/ground_units/house2arm.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 0 -variants: - Watch tower armed: null -hit_points: 10 diff --git a/resources/units/ground_units/hy_launcher.yaml b/resources/units/ground_units/hy_launcher.yaml deleted file mode 100644 index ef306e4e3..000000000 --- a/resources/units/ground_units/hy_launcher.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: AntiShipMissile -price: 0 -reversed_heading: true # Needs to be placed backwards! -variants: - AShM SS-N-2 Silkworm: null -hit_points: 4 diff --git a/resources/units/ground_units/leopard-2A4.yaml b/resources/units/ground_units/leopard-2A4.yaml deleted file mode 100644 index 23b17aeb9..000000000 --- a/resources/units/ground_units/leopard-2A4.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The Leopard 2 is a main battle tank developed by Krauss-Maffei in the - 1970s for the West German Army. The tank first entered service in 1979 and succeeded - the earlier Leopard 1 as the main battle tank of the German Army. It is armed with - a 120 mm smoothbore cannon, and is powered by a V-12 twin-turbo diesel engine. Various - versions have served in the armed forces of Germany and 12 other European countries, - as well as several non-European nations, including Canada, Chile, Indonesia, Singapore, - and Turkey. The Leopard 2 was used in Kosovo with the German Army, and has seen - action in Afghanistan with the Dutch, Danish and Canadian contributions to the International - Security Assistance Force, as well as seeing action in Syria with the Turkish Armed - Forces. -introduced: 1991 -manufacturer: Krauss-Maffei -origin: Germany -price: 20 -role: Main Battle Tank -variants: - Leopard 2A4: {} -hit_points: 32 diff --git a/resources/units/ground_units/leopard-2A4_trs.yaml b/resources/units/ground_units/leopard-2A4_trs.yaml deleted file mode 100644 index d574c6078..000000000 --- a/resources/units/ground_units/leopard-2A4_trs.yaml +++ /dev/null @@ -1,19 +0,0 @@ -class: Tank -description: The Leopard 2 is a main battle tank developed by Krauss-Maffei in the - 1970s for the West German Army. The tank first entered service in 1979 and succeeded - the earlier Leopard 1 as the main battle tank of the German Army. It is armed with - a 120 mm smoothbore cannon, and is powered by a V-12 twin-turbo diesel engine. Various - versions have served in the armed forces of Germany and 12 other European countries, - as well as several non-European nations, including Canada, Chile, Indonesia, Singapore, - and Turkey. The Leopard 2 was used in Kosovo with the German Army, and has seen - action in Afghanistan with the Dutch, Danish and Canadian contributions to the International - Security Assistance Force, as well as seeing action in Syria with the Turkish Armed - Forces. -introduced: 1991 -manufacturer: Krauss-Maffei -origin: Germany -price: 20 -role: Main Battle Tank -variants: - Leopard 2A4 Trs: {} -hit_points: 32 diff --git a/resources/units/ground_units/p-19 s-125 sr.yaml b/resources/units/ground_units/p-19 s-125 sr.yaml deleted file mode 100644 index 88d2db1a4..000000000 --- a/resources/units/ground_units/p-19 s-125 sr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: SearchRadar -price: 14 -variants: - SAM P19 "Flat Face" SR (SA-2/3): null -hit_points: 2 diff --git a/resources/units/ground_units/polyana-d4m1 cp.yaml b/resources/units/ground_units/polyana-d4m1 cp.yaml deleted file mode 100644 index ebc2eff89..000000000 --- a/resources/units/ground_units/polyana-d4m1 cp.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: CommandPost -price: 14 -variants: - Polyana-D4M1 C2 node: null diff --git a/resources/units/ground_units/rapier_fsa_blindfire_radar.yaml b/resources/units/ground_units/rapier_fsa_blindfire_radar.yaml deleted file mode 100644 index ff5a42a64..000000000 --- a/resources/units/ground_units/rapier_fsa_blindfire_radar.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 8 -variants: - SAM Rapier Blindfire TR: null -hit_points: 3 diff --git a/resources/units/ground_units/rapier_fsa_launcher.yaml b/resources/units/ground_units/rapier_fsa_launcher.yaml deleted file mode 100644 index 4219dd9c6..000000000 --- a/resources/units/ground_units/rapier_fsa_launcher.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Launcher -price: 6 -variants: - SAM Rapier LN: null -hit_points: 3 diff --git a/resources/units/ground_units/rapier_fsa_optical_tracker_unit.yaml b/resources/units/ground_units/rapier_fsa_optical_tracker_unit.yaml deleted file mode 100644 index 813a3b1df..000000000 --- a/resources/units/ground_units/rapier_fsa_optical_tracker_unit.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: OpticalTracker -price: 6 -variants: - SAM Rapier Tracker: null -hit_points: 3 diff --git a/resources/units/ground_units/snr s-125 tr.yaml b/resources/units/ground_units/snr s-125 tr.yaml deleted file mode 100644 index 392057d33..000000000 --- a/resources/units/ground_units/snr s-125 tr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: TrackRadar -price: 14 -variants: - SAM SA-3 S-125 "Low Blow" TR: null -hit_points: 2 diff --git a/resources/units/ground_units/soldier_mauser98.yaml b/resources/units/ground_units/soldier_mauser98.yaml deleted file mode 100644 index 5df631d51..000000000 --- a/resources/units/ground_units/soldier_mauser98.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 4 -variants: - Infantry Mauser 98: null -hit_points: 1 diff --git a/resources/units/ground_units/soldier_wwii_br_01.yaml b/resources/units/ground_units/soldier_wwii_br_01.yaml deleted file mode 100644 index c5d3c2d94..000000000 --- a/resources/units/ground_units/soldier_wwii_br_01.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 3 -variants: - Infantry SMLE No.4 Mk-1: null -hit_points: 1 diff --git a/resources/units/ground_units/soldier_wwii_us.yaml b/resources/units/ground_units/soldier_wwii_us.yaml deleted file mode 100644 index 3e593d9fd..000000000 --- a/resources/units/ground_units/soldier_wwii_us.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Infantry -price: 0 -spawn_weight: 3 -variants: - Infantry M1 Garand: null -hit_points: 1 diff --git a/resources/units/ground_units/tt_B8M1.yaml b/resources/units/ground_units/tt_B8M1.yaml deleted file mode 100644 index fb45706cd..000000000 --- a/resources/units/ground_units/tt_B8M1.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: Artillery -price: 10 -role: Multiple-Launch Rocket System -variants: - MLRS LC with B8M1 80mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/tt_DSHK.yaml b/resources/units/ground_units/tt_DSHK.yaml deleted file mode 100644 index e55c2255e..000000000 --- a/resources/units/ground_units/tt_DSHK.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: APC -price: 4 -role: Recon -variants: - Scout LC with DSHK 12.7mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/tt_KORD.yaml b/resources/units/ground_units/tt_KORD.yaml deleted file mode 100644 index f6eb2314b..000000000 --- a/resources/units/ground_units/tt_KORD.yaml +++ /dev/null @@ -1,6 +0,0 @@ -class: APC -price: 4 -role: Recon -variants: - Scout LC with KORD 12.7mm: {} -hit_points: 1 diff --git a/resources/units/ground_units/tt_ZU-23.yaml b/resources/units/ground_units/tt_ZU-23.yaml deleted file mode 100644 index be1103d42..000000000 --- a/resources/units/ground_units/tt_ZU-23.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AAA -price: 6 -variants: - SPAAA LC with ZU-23: null -hit_points: 1 diff --git a/resources/units/ground_units/v1_launcher.yaml b/resources/units/ground_units/v1_launcher.yaml deleted file mode 100644 index b64c7907c..000000000 --- a/resources/units/ground_units/v1_launcher.yaml +++ /dev/null @@ -1,4 +0,0 @@ -class: Missile -variants: - V-1 Launch Ramp: null -hit_points: 4 diff --git a/resources/units/ships/ALBATROS.yaml b/resources/units/ships/ALBATROS.yaml deleted file mode 100644 index 25003743f..000000000 --- a/resources/units/ships/ALBATROS.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - Corvette 1124.4 Grish: null -hit_points: 1600 diff --git a/resources/units/ships/BDK-775.yaml b/resources/units/ships/BDK-775.yaml deleted file mode 100644 index 12fbb5597..000000000 --- a/resources/units/ships/BDK-775.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: LandingShip -price: 0 -variants: - LS Ropucha: null -hit_points: 2000 diff --git a/resources/units/ships/CastleClass_01.yaml b/resources/units/ships/CastleClass_01.yaml deleted file mode 100644 index c3357e4c0..000000000 --- a/resources/units/ships/CastleClass_01.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Boat -price: 0 -variants: - Castle Class: null -hit_points: 1200 diff --git a/resources/units/ships/Forrestal.yaml b/resources/units/ships/Forrestal.yaml deleted file mode 100644 index 265e2cc4d..000000000 --- a/resources/units/ships/Forrestal.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AircraftCarrier -price: 0 -variants: - CV-59 Forrestal: null -hit_points: 7300 diff --git a/resources/units/ships/HandyWind.yaml b/resources/units/ships/HandyWind.yaml deleted file mode 100644 index 2a2246e41..000000000 --- a/resources/units/ships/HandyWind.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Boat -price: 0 -variants: - Handy Wind: null -hit_points: 1000 diff --git a/resources/units/ships/Higgins_boat.yaml b/resources/units/ships/Higgins_boat.yaml deleted file mode 100644 index e233a313c..000000000 --- a/resources/units/ships/Higgins_boat.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: LandingShip -price: 0 -variants: - Boat LCVP Higgins: null -hit_points: 4 diff --git a/resources/units/ships/IMPROVED_KILO.yaml b/resources/units/ships/IMPROVED_KILO.yaml deleted file mode 100644 index 2ca1798dc..000000000 --- a/resources/units/ships/IMPROVED_KILO.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Submarine -price: 0 -variants: - SSK 636 Improved Kilo: null -hit_points: 300 diff --git a/resources/units/ships/KILO.yaml b/resources/units/ships/KILO.yaml deleted file mode 100644 index dd0f20484..000000000 --- a/resources/units/ships/KILO.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Submarine -price: 0 -variants: - SSK 877V Kilo: null -hit_points: 300 diff --git a/resources/units/ships/KUZNECOW.yaml b/resources/units/ships/KUZNECOW.yaml deleted file mode 100644 index ae64a1847..000000000 --- a/resources/units/ships/KUZNECOW.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AircraftCarrier -price: 0 -variants: - CV 1143.5 Admiral Kuznetsov: null -hit_points: 7000 diff --git a/resources/units/ships/LHA_Tarawa.yaml b/resources/units/ships/LHA_Tarawa.yaml deleted file mode 100644 index d8ba2d94b..000000000 --- a/resources/units/ships/LHA_Tarawa.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: HelicopterCarrier -price: 0 -variants: - LHA-1 Tarawa: null -hit_points: 7300 diff --git a/resources/units/ships/LST_Mk2.yaml b/resources/units/ships/LST_Mk2.yaml deleted file mode 100644 index 91f56a6db..000000000 --- a/resources/units/ships/LST_Mk2.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: LandingShip -price: 0 -variants: - LST Mk.II: null -hit_points: 2100 diff --git a/resources/units/ships/La_Combattante_II.yaml b/resources/units/ships/La_Combattante_II.yaml deleted file mode 100644 index 4ab1f3ebd..000000000 --- a/resources/units/ships/La_Combattante_II.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - FAC La Combattante IIa: null -hit_points: 750 diff --git a/resources/units/ships/MOLNIYA.yaml b/resources/units/ships/MOLNIYA.yaml deleted file mode 100644 index 09d153335..000000000 --- a/resources/units/ships/MOLNIYA.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - Corvette 1241.1 Molniya: null -hit_points: 700 diff --git a/resources/units/ships/MOSCOW.yaml b/resources/units/ships/MOSCOW.yaml deleted file mode 100644 index deef292a2..000000000 --- a/resources/units/ships/MOSCOW.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Cruiser -price: 0 -variants: - Cruiser 1164 Moskva: null -hit_points: 5200 diff --git a/resources/units/ships/NEUSTRASH.yaml b/resources/units/ships/NEUSTRASH.yaml deleted file mode 100644 index 3bbdc1eb2..000000000 --- a/resources/units/ships/NEUSTRASH.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - Frigate 11540 Neustrashimy: null -hit_points: 2180 diff --git a/resources/units/ships/PERRY.yaml b/resources/units/ships/PERRY.yaml deleted file mode 100644 index db28b65dc..000000000 --- a/resources/units/ships/PERRY.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - FFG Oliver Hazard Perry: null -hit_points: 2100 diff --git a/resources/units/ships/REZKY.yaml b/resources/units/ships/REZKY.yaml deleted file mode 100644 index 8d2296f94..000000000 --- a/resources/units/ships/REZKY.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - Frigate 1135M Rezky: null -hit_points: 1800 diff --git a/resources/units/ships/Schnellboot_type_S130.yaml b/resources/units/ships/Schnellboot_type_S130.yaml deleted file mode 100644 index b2c90eef4..000000000 --- a/resources/units/ships/Schnellboot_type_S130.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Boat -price: 0 -variants: - Boat Schnellboot type S130: null -hit_points: 50 diff --git a/resources/units/ships/Stennis.yaml b/resources/units/ships/Stennis.yaml deleted file mode 100644 index 3d511d04b..000000000 --- a/resources/units/ships/Stennis.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: AircraftCarrier -price: 0 -variants: - CVN-74 John C. Stennis: null -hit_points: 7300 diff --git a/resources/units/ships/TICONDEROG.yaml b/resources/units/ships/TICONDEROG.yaml deleted file mode 100644 index 1d4e22e1a..000000000 --- a/resources/units/ships/TICONDEROG.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Cruiser -price: 0 -variants: - CG Ticonderoga: null -hit_points: 2700 diff --git a/resources/units/ships/Type_052B.yaml b/resources/units/ships/Type_052B.yaml deleted file mode 100644 index 00a6cc96a..000000000 --- a/resources/units/ships/Type_052B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - Type 052B Destroyer: null -hit_points: 2700 diff --git a/resources/units/ships/Type_052C.yaml b/resources/units/ships/Type_052C.yaml deleted file mode 100644 index ad10dce6a..000000000 --- a/resources/units/ships/Type_052C.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - Type 052C Destroyer: null -hit_points: 3200 diff --git a/resources/units/ships/Type_054A.yaml b/resources/units/ships/Type_054A.yaml deleted file mode 100644 index 6dc630a23..000000000 --- a/resources/units/ships/Type_054A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - Type 054A Frigate: null -hit_points: 2500 diff --git a/resources/units/ships/Type_071.yaml b/resources/units/ships/Type_071.yaml deleted file mode 100644 index 0aa5865f9..000000000 --- a/resources/units/ships/Type_071.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: HelicopterCarrier -price: 0 -variants: - Type 071 Amphibious Transport Dock: null -hit_points: 7300 diff --git a/resources/units/ships/Type_093.yaml b/resources/units/ships/Type_093.yaml deleted file mode 100644 index 3644b7bb4..000000000 --- a/resources/units/ships/Type_093.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Submarine -price: 0 -variants: - Type 093 Attack Submarine: null -hit_points: 1500 diff --git a/resources/units/ships/USS_Arleigh_Burke_IIa.yaml b/resources/units/ships/USS_Arleigh_Burke_IIa.yaml deleted file mode 100644 index f310b7789..000000000 --- a/resources/units/ships/USS_Arleigh_Burke_IIa.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Destroyer -price: 0 -variants: - DDG Arleigh Burke IIa: null -hit_points: 2100 diff --git a/resources/units/ships/USS_Samuel_Chase.yaml b/resources/units/ships/USS_Samuel_Chase.yaml deleted file mode 100644 index 1106ec3c8..000000000 --- a/resources/units/ships/USS_Samuel_Chase.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Boat -price: 0 -variants: - LS Samuel Chase: null -hit_points: 2100 diff --git a/resources/units/ships/Uboat_VIIC.yaml b/resources/units/ships/Uboat_VIIC.yaml deleted file mode 100644 index 5af2bc209..000000000 --- a/resources/units/ships/Uboat_VIIC.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Submarine -price: 0 -variants: - U-boat VIIC U-flak: null -hit_points: 800 diff --git a/resources/units/ships/ara_vdm.yaml b/resources/units/ships/ara_vdm.yaml deleted file mode 100644 index bfd21f0f6..000000000 --- a/resources/units/ships/ara_vdm.yaml +++ /dev/null @@ -1,7 +0,0 @@ -class: AircraftCarrier -price: 0 -variants: - ARA Vienticinco de Mayo: {} - ARA Veinticinco de Mayo: {} - HMAS Melbourne: {} -hit_points: 7200 diff --git a/resources/units/ships/hms_invincible.yaml b/resources/units/ships/hms_invincible.yaml deleted file mode 100644 index be454f3ba..000000000 --- a/resources/units/ships/hms_invincible.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: HelicopterCarrier -price: 0 -variants: - HMS Invincible (R05): null -hit_points: 7200 diff --git a/resources/units/ships/leander-gun-achilles.yaml b/resources/units/ships/leander-gun-achilles.yaml deleted file mode 100644 index 5cf98ae93..000000000 --- a/resources/units/ships/leander-gun-achilles.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - HMS Achilles (F12): null -hit_points: 1000 diff --git a/resources/units/ships/leander-gun-andromeda.yaml b/resources/units/ships/leander-gun-andromeda.yaml deleted file mode 100644 index b685fce2b..000000000 --- a/resources/units/ships/leander-gun-andromeda.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - HMS Andromeda (F57): null -hit_points: 1000 diff --git a/resources/units/ships/leander-gun-ariadne.yaml b/resources/units/ships/leander-gun-ariadne.yaml deleted file mode 100644 index f3a171ff3..000000000 --- a/resources/units/ships/leander-gun-ariadne.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - HMS Ariadne (F72): null -hit_points: 1000 diff --git a/resources/units/ships/leander-gun-condell.yaml b/resources/units/ships/leander-gun-condell.yaml deleted file mode 100644 index c084b469b..000000000 --- a/resources/units/ships/leander-gun-condell.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - CNS Almirante Condell (PFG-06): null -hit_points: 1000 diff --git a/resources/units/ships/leander-gun-lynch.yaml b/resources/units/ships/leander-gun-lynch.yaml deleted file mode 100644 index 886657a03..000000000 --- a/resources/units/ships/leander-gun-lynch.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Frigate -price: 0 -variants: - CNS Almirante Lynch (PFG-07): null -hit_points: 1000 diff --git a/resources/units/ships/santafe.yaml b/resources/units/ships/santafe.yaml deleted file mode 100644 index b0ea75a79..000000000 --- a/resources/units/ships/santafe.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Submarine -price: 0 -variants: - ARA Santa Fe S-21: null -hit_points: 100 diff --git a/resources/units/ships/speedboat.yaml b/resources/units/ships/speedboat.yaml deleted file mode 100644 index b37a56745..000000000 --- a/resources/units/ships/speedboat.yaml +++ /dev/null @@ -1,5 +0,0 @@ -class: Boat -price: 0 -variants: - Boat Armed Hi-speed: null -hit_points: 1 diff --git a/resources/weapons/a2a-missiles/AIM-120B-2X.yaml b/resources/weapons/a2a-missiles/AIM-120B-2X.yaml deleted file mode 100644 index 736cb20a4..000000000 --- a/resources/weapons/a2a-missiles/AIM-120B-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAIM-120B -year: 1994 -# If we've run out of doubles, start over with the singles. -fallback: AIM-120C -clsids: - - "LAU-115_2*LAU-127_AIM-120B" diff --git a/resources/weapons/a2a-missiles/AIM-120B.yaml b/resources/weapons/a2a-missiles/AIM-120B.yaml deleted file mode 100644 index de0db7187..000000000 --- a/resources/weapons/a2a-missiles/AIM-120B.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AIM-120B -year: 1994 -# B model IOC in 1994, HOWEVER A model IOC in 1991 with USAF and 1993 with USN on Hornet -fallback: AIM-7P -clsids: - - "{C8E06185-7CD6-4C90-959F-044679E90751}" - - "{LAU-115 - AIM-120B}" - - "{LAU-115 - AIM-120B_R}" diff --git a/resources/weapons/a2a-missiles/AIM-120C-2X.yaml b/resources/weapons/a2a-missiles/AIM-120C-2X.yaml deleted file mode 100644 index 95d4a0895..000000000 --- a/resources/weapons/a2a-missiles/AIM-120C-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xAIM-120C -year: 1996 -fallback: 2xAIM-120B -clsids: - - "LAU-115_2*LAU-127_AIM-120C" diff --git a/resources/weapons/a2a-missiles/AIM-120C.yaml b/resources/weapons/a2a-missiles/AIM-120C.yaml deleted file mode 100644 index 2098e2b88..000000000 --- a/resources/weapons/a2a-missiles/AIM-120C.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-120C -year: 1996 -fallback: AIM-120B -clsids: - - "{40EF17B7-F508-45de-8566-6FFECC0C1AB8}" - - "{LAU-115 - AIM-120C}" - - "{LAU-115 - AIM-120C_R}" diff --git a/resources/weapons/a2a-missiles/AIM-54A-MK47.yaml b/resources/weapons/a2a-missiles/AIM-54A-MK47.yaml deleted file mode 100644 index 7d83432eb..000000000 --- a/resources/weapons/a2a-missiles/AIM-54A-MK47.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-54A-MK47 -year: 1974 -fallback: AIM-7MH -clsids: - - "{SHOULDER AIM_54A_Mk47 R}" - - "{SHOULDER AIM_54A_Mk47 L}" - - "{AIM_54A_Mk47}" diff --git a/resources/weapons/a2a-missiles/AIM-54A-MK60.yaml b/resources/weapons/a2a-missiles/AIM-54A-MK60.yaml deleted file mode 100644 index 6e49ad784..000000000 --- a/resources/weapons/a2a-missiles/AIM-54A-MK60.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-54A-MK60 -year: 1975 -fallback: AIM-54A-MK47 -clsids: - - "{SHOULDER AIM_54A_Mk60 R}" - - "{SHOULDER AIM_54A_Mk60 L}" - - "{AIM_54A_Mk60}" diff --git a/resources/weapons/a2a-missiles/AIM-54C-MK47.yaml b/resources/weapons/a2a-missiles/AIM-54C-MK47.yaml deleted file mode 100644 index 1e88c3ee2..000000000 --- a/resources/weapons/a2a-missiles/AIM-54C-MK47.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-54C-MK47 -year: 1986 -fallback: AIM-54A-MK60 -clsids: - - "{SHOULDER AIM_54C_Mk47 R}" - - "{SHOULDER AIM_54C_Mk47 L}" - - "{AIM_54C_Mk47}" diff --git a/resources/weapons/a2a-missiles/AIM-54C-MK60.yaml b/resources/weapons/a2a-missiles/AIM-54C-MK60.yaml deleted file mode 100644 index 3ef426aed..000000000 --- a/resources/weapons/a2a-missiles/AIM-54C-MK60.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-54C-MK60 -year: 1986 -fallback: AIM-54C-MK47 -clsids: - - "{SHOULDER AIM_54C_Mk60 R}" - - "{SHOULDER AIM_54C_Mk60 L}" - - "{AIM_54C_Mk60}" diff --git a/resources/weapons/a2a-missiles/AIM-7E.yaml b/resources/weapons/a2a-missiles/AIM-7E.yaml deleted file mode 100644 index bbc70d1e7..000000000 --- a/resources/weapons/a2a-missiles/AIM-7E.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AIM-7E -year: 1963 -fallback: 2xAIM-9X -clsids: - - "{AIM-7E}" - - "{LAU-115 - AIM-7E}" diff --git a/resources/weapons/a2a-missiles/AIM-7F.yaml b/resources/weapons/a2a-missiles/AIM-7F.yaml deleted file mode 100644 index d66fd3b85..000000000 --- a/resources/weapons/a2a-missiles/AIM-7F.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AIM-7F -year: 1976 -fallback: AIM-7E -clsids: - - "{SHOULDER AIM-7F}" - - "{BELLY AIM-7F}" - - "{AIM-7F}" - - "{LAU-115 - AIM-7F}" diff --git a/resources/weapons/a2a-missiles/AIM-7M.yaml b/resources/weapons/a2a-missiles/AIM-7M.yaml deleted file mode 100644 index 9128c8ed9..000000000 --- a/resources/weapons/a2a-missiles/AIM-7M.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AIM-7M -year: 1982 -fallback: AIM-7F -clsids: - - "{SHOULDER AIM-7M}" - - "{BELLY AIM-7M}" - - "{8D399DDA-FF81-4F14-904D-099B34FE7918}" - - "{LAU-115 - AIM-7M}" diff --git a/resources/weapons/a2a-missiles/AIM-7MH.yaml b/resources/weapons/a2a-missiles/AIM-7MH.yaml deleted file mode 100644 index e2d15b341..000000000 --- a/resources/weapons/a2a-missiles/AIM-7MH.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AIM-7MH -year: 1987 -fallback: AIM-7M -clsids: - - "{SHOULDER AIM-7MH}" - - "{BELLY AIM-7MH}" - - "{AIM-7H}" - - "{LAU-115 - AIM-7H}" diff --git a/resources/weapons/a2a-missiles/AIM-7P.yaml b/resources/weapons/a2a-missiles/AIM-7P.yaml deleted file mode 100644 index e32477088..000000000 --- a/resources/weapons/a2a-missiles/AIM-7P.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: AIM-7P -year: 1992 -#Entered Production in 1987 but doesn't appear to have actually achieved IOC until 1992 -fallback: AIM-7MH -clsids: - - "{SHOULDER AIM-7P}" - - "{BELLY AIM-7P}" - - "{AIM-7P}" - - "{LAU-115 - AIM-7P}" diff --git a/resources/weapons/a2a-missiles/AIM-9B-2X.yaml b/resources/weapons/a2a-missiles/AIM-9B-2X.yaml deleted file mode 100644 index 25f6f2c98..000000000 --- a/resources/weapons/a2a-missiles/AIM-9B-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAIM-9B -year: 1956 -# have gone through the doubles so now back to the singles -fallback: AIM-9X -clsids: - - "{F4-2-AIM9B}" diff --git a/resources/weapons/a2a-missiles/AIM-9B.yaml b/resources/weapons/a2a-missiles/AIM-9B.yaml deleted file mode 100644 index 57fdb699d..000000000 --- a/resources/weapons/a2a-missiles/AIM-9B.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-9B -year: 1956 -clsids: - - "{AIM-9B}" - - "{GAR-8}" - - "{Robot24}" - - "{Rb_24}" diff --git a/resources/weapons/a2a-missiles/AIM-9J-2X.yaml b/resources/weapons/a2a-missiles/AIM-9J-2X.yaml deleted file mode 100644 index 0ada01902..000000000 --- a/resources/weapons/a2a-missiles/AIM-9J-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAIM-9J -year: 1972 -#IOC is in 1977, but was fielded in 1972 - using field date since the 9B is terrible and there are no versions in between in DCS -fallback: 2xAIM-9B -clsids: - - "{VSN_F4B_LAU105_AIM9J}" diff --git a/resources/weapons/a2a-missiles/AIM-9J.yaml b/resources/weapons/a2a-missiles/AIM-9J.yaml deleted file mode 100644 index 76ced6682..000000000 --- a/resources/weapons/a2a-missiles/AIM-9J.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-9J -year: 1972 -#IOC is in 1977, but was fielded in 1972 - using field date since the 9B is terrible and there are no versions in between in DCS -fallback: AIM-9B -clsids: - - "{AIM-9J}" - - "{AIM-9J-ON-ADAPTER}" diff --git a/resources/weapons/a2a-missiles/AIM-9Juli-2X.yaml b/resources/weapons/a2a-missiles/AIM-9Juli-2X.yaml deleted file mode 100644 index 29414f154..000000000 --- a/resources/weapons/a2a-missiles/AIM-9Juli-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAIM-9Juli -year: 1990 -#BGT (German Company) upgrade to Spains existing 9J with L seeker, production started in 1990 (https://apps.dtic.mil/sti/pdfs/ADA278261.pdf); overall performance somewhere between 9P4 and 9P5 in real life but between 9P5 and 9L in DCS -fallback: 2xAIM-9P5 -clsids: - - "{VSN_F4B_LAU105_AIM9JULI}" diff --git a/resources/weapons/a2a-missiles/AIM-9Juli.yaml b/resources/weapons/a2a-missiles/AIM-9Juli.yaml deleted file mode 100644 index 287c70e70..000000000 --- a/resources/weapons/a2a-missiles/AIM-9Juli.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AIM-9Juli -year: 1990 -#BGT (German Company) upgrade to Spains existing 9J with L seeker, production started in 1990 (https://apps.dtic.mil/sti/pdfs/ADA278261.pdf); overall performance somewhere between 9P4 and 9P5 in real life but between 9P5 and 9L in DCS -fallback: AIM-9P5 -clsids: - - "{AIM-9Juli}" diff --git a/resources/weapons/a2a-missiles/AIM-9L-2X.yaml b/resources/weapons/a2a-missiles/AIM-9L-2X.yaml deleted file mode 100644 index 6b9bcd9f3..000000000 --- a/resources/weapons/a2a-missiles/AIM-9L-2X.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: 2xAIM-9L -year: 1977 -fallback: 2xAIM-9Juli -clsids: - - "LAU-105_2*AIM-9L" - - "LAU-115_2*LAU-127_AIM-9L" - - "{F4-2-AIM9L}" - - "{VSN_F104_LAU105_AIM9L}" - - "{VSN_F104_LAU115C_AIM9L}" diff --git a/resources/weapons/a2a-missiles/AIM-9L.yaml b/resources/weapons/a2a-missiles/AIM-9L.yaml deleted file mode 100644 index 12ca45fd8..000000000 --- a/resources/weapons/a2a-missiles/AIM-9L.yaml +++ /dev/null @@ -1,16 +0,0 @@ -name: AIM-9L -year: 1977 -fallback: AIM-9Juli -clsids: - - "{AIM-9L}" - - "LAU-105_1*AIM-9L_L" - - "LAU-105_1*AIM-9L_R" - - "LAU-115_LAU-127_AIM-9L" - - "LAU-115_LAU-127_AIM-9L_R" - - "LAU-127_AIM-9L" - - "{LAU-138 wtip - AIM-9L}" - - "{LAU-7 - AIM-9L}" - - "{AIM-9L-ON-ADAPTER}" - - "{JAS39_AIM-9L}" - - "{Rb_74}" - - "{Robot74}" diff --git a/resources/weapons/a2a-missiles/AIM-9M-2X.yaml b/resources/weapons/a2a-missiles/AIM-9M-2X.yaml deleted file mode 100644 index 11de3784e..000000000 --- a/resources/weapons/a2a-missiles/AIM-9M-2X.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: 2xAIM-9M -year: 1982 -fallback: 2xAIM-9L -clsids: - - "{DB434044-F5D0-4F1F-9BA9-B73027E18DD3}" - - "LAU-115_2*LAU-127_AIM-9M" - - "{9DDF5297-94B9-42FC-A45E-6E316121CD85}" diff --git a/resources/weapons/a2a-missiles/AIM-9M.yaml b/resources/weapons/a2a-missiles/AIM-9M.yaml deleted file mode 100644 index 66fce2296..000000000 --- a/resources/weapons/a2a-missiles/AIM-9M.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: AIM-9M -year: 1982 -fallback: AIM-9L -clsids: - - "{6CEB49FC-DED8-4DED-B053-E1F033FF72D3}" - - "LAU-105_1*AIM-9M_L" - - "LAU-105_1*AIM-9M_R" - - "LAU-115_LAU-127_AIM-9M" - - "LAU-115_LAU-127_AIM-9M_R" - - "LAU-127_AIM-9M" - - "{LAU-138 wtip - AIM-9M}" - - "{LAU-7 - AIM-9M}" - - "{AIM-9M-ON-ADAPTER}" - - "{JAS39_AIM-9M}" diff --git a/resources/weapons/a2a-missiles/AIM-9P-2X.yaml b/resources/weapons/a2a-missiles/AIM-9P-2X.yaml deleted file mode 100644 index c4bfc9e8c..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P-2X.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: 2xAIM-9P -year: 1978 -#IOC is in 1978, but is an upgrade to the J so can be used as a stand in for earlier aim-9 models missing from DCS or certain mods. -fallback: 2xAIM-9J -clsids: - - "{3C0745ED-8B0B-42eb-B907-5BD5C1717447}" - - "{773675AB-7C29-422f-AFD8-32844A7B7F17}" - - "{VSN_F104_LAU105_AIM9P}" - - "{VSN_F104_LAU115C_AIM9P}" diff --git a/resources/weapons/a2a-missiles/AIM-9P.yaml b/resources/weapons/a2a-missiles/AIM-9P.yaml deleted file mode 100644 index 269df428a..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AIM-9P -year: 1978 -#IOC is in 1978, but is an upgrade to the J so can be used as a stand in for earlier aim-9 models missing from DCS or certain mods. -fallback: AIM-9J -clsids: - - "{9BFD8C90-F7AE-4e90-833B-BFD0CED0E536}" - - "{AIM-9P-ON-ADAPTER}" diff --git a/resources/weapons/a2a-missiles/AIM-9P3-2X.yaml b/resources/weapons/a2a-missiles/AIM-9P3-2X.yaml deleted file mode 100644 index b31a5aa89..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P3-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xAIM-9P3 -year: 1979 -fallback: 2xAIM-9P -clsids: - - "LAU-105_2*AIM-9P3" diff --git a/resources/weapons/a2a-missiles/AIM-9P3.yaml b/resources/weapons/a2a-missiles/AIM-9P3.yaml deleted file mode 100644 index dc9af37f5..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P3.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: AIM-9P3 -year: 1979 -fallback: AIM-9P -clsids: - - "{AIM-9P3}" - - "{AIM-9P3-ON-ADAPTER}" - - "{A4E-AIM-9P3-ON-ADAPTER}" - - "{Robot24J}" - - "{Rb_24J}" diff --git a/resources/weapons/a2a-missiles/AIM-9P5-2X.yaml b/resources/weapons/a2a-missiles/AIM-9P5-2X.yaml deleted file mode 100644 index 96f24822e..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P5-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAIM-9P5 -year: 1980 -fallback: 2xAIM-9P3 -clsids: - - "LAU-105_2*AIM-9P5" - - "{F4-2-AIM9P5}" diff --git a/resources/weapons/a2a-missiles/AIM-9P5.yaml b/resources/weapons/a2a-missiles/AIM-9P5.yaml deleted file mode 100644 index ae0d37636..000000000 --- a/resources/weapons/a2a-missiles/AIM-9P5.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AIM-9P5 -year: 1980 -fallback: AIM-9P3 -clsids: - - "{AIM-9P5}" - - "{AIM-9P5-ON-ADAPTER}" diff --git a/resources/weapons/a2a-missiles/AIM-9X-2X.yaml b/resources/weapons/a2a-missiles/AIM-9X-2X.yaml deleted file mode 100644 index 3496f279e..000000000 --- a/resources/weapons/a2a-missiles/AIM-9X-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xAIM-9X -year: 2003 -fallback: 2xAIM-9M -clsids: - - "LAU-115_2*LAU-127_AIM-9X" diff --git a/resources/weapons/a2a-missiles/AIM-9X.yaml b/resources/weapons/a2a-missiles/AIM-9X.yaml deleted file mode 100644 index bec1ddc07..000000000 --- a/resources/weapons/a2a-missiles/AIM-9X.yaml +++ /dev/null @@ -1,9 +0,0 @@ -name: AIM-9X -year: 2003 -fallback: AIM-9M -clsids: - - "{5CE2FF2A-645A-4197-B48D-8720AC69394F}" - - "LAU-115_LAU-127_AIM-9X" - - "LAU-115_LAU-127_AIM-9X_R" - - "LAU-127_AIM-9X" - - "{AIM-9X-ON-ADAPTER}" diff --git a/resources/weapons/a2a-missiles/K-13A.yaml b/resources/weapons/a2a-missiles/K-13A.yaml deleted file mode 100644 index 799cd4ace..000000000 --- a/resources/weapons/a2a-missiles/K-13A.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: K-13A -year: 1962 -clsids: - - "{K-13A}" diff --git a/resources/weapons/a2a-missiles/R-13M.yaml b/resources/weapons/a2a-missiles/R-13M.yaml deleted file mode 100644 index 97a988763..000000000 --- a/resources/weapons/a2a-missiles/R-13M.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-13M - AAM, IR guided -year: 1974 -fallback: R-60 -clsids: - - "{R-13M}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-13M1.yaml b/resources/weapons/a2a-missiles/R-13M1.yaml deleted file mode 100644 index 9b44024ac..000000000 --- a/resources/weapons/a2a-missiles/R-13M1.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-13M1 - AAM, IR guided -year: 1976 -fallback: R-13M - AAM, IR guided -clsids: - - "{R-13M1}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-24R.yaml b/resources/weapons/a2a-missiles/R-24R.yaml deleted file mode 100644 index 1e1db0948..000000000 --- a/resources/weapons/a2a-missiles/R-24R.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-24R -year: 1981 -fallback: R-3R - AAM, radar guided -clsids: - - "{CCF898C9-5BC7-49A4-9D1E-C3ED3D5166A1}" diff --git a/resources/weapons/a2a-missiles/R-24T.yaml b/resources/weapons/a2a-missiles/R-24T.yaml deleted file mode 100644 index 25d7aa8b5..000000000 --- a/resources/weapons/a2a-missiles/R-24T.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-24T -year: 1981 -fallback: R-24R -clsids: - - "{6980735A-44CC-4BB9-A1B5-591532F1DC69}" diff --git a/resources/weapons/a2a-missiles/R-27ER.yaml b/resources/weapons/a2a-missiles/R-27ER.yaml deleted file mode 100644 index 7f93913f5..000000000 --- a/resources/weapons/a2a-missiles/R-27ER.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-27ER -year: 1990 # Based on deagal.com may have been earlier -fallback: R-27R -clsids: - - "{E8069896-8435-4B90-95C0-01A03AE6E400}" diff --git a/resources/weapons/a2a-missiles/R-27ET.yaml b/resources/weapons/a2a-missiles/R-27ET.yaml deleted file mode 100644 index 3769f9b54..000000000 --- a/resources/weapons/a2a-missiles/R-27ET.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-27ET -year: 1990 # Based on deagal.com may have been earlier -fallback: R-27T -clsids: - - "{B79C379A-9E87-4E50-A1EE-7F7E29C2E87A}" diff --git a/resources/weapons/a2a-missiles/R-27R.yaml b/resources/weapons/a2a-missiles/R-27R.yaml deleted file mode 100644 index 3f9edc942..000000000 --- a/resources/weapons/a2a-missiles/R-27R.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-27R -year: 1983 -fallback: R-24R -clsids: - - "{9B25D316-0434-4954-868F-D51DB1A38DF0}" diff --git a/resources/weapons/a2a-missiles/R-27T.yaml b/resources/weapons/a2a-missiles/R-27T.yaml deleted file mode 100644 index c9232ef60..000000000 --- a/resources/weapons/a2a-missiles/R-27T.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-27T -year: 1983 -fallback: R-24T -clsids: - - "{88DAC840-9F75-4531-8689-B46E64E42E53}" diff --git a/resources/weapons/a2a-missiles/R-3R.yaml b/resources/weapons/a2a-missiles/R-3R.yaml deleted file mode 100644 index 4a410d1f3..000000000 --- a/resources/weapons/a2a-missiles/R-3R.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-3R - AAM, radar guided -year: 1966 -fallback: R-3S - AAM, IR guided -clsids: - - "{R-3R}" diff --git a/resources/weapons/a2a-missiles/R-3S.yaml b/resources/weapons/a2a-missiles/R-3S.yaml deleted file mode 100644 index 9d6ee396d..000000000 --- a/resources/weapons/a2a-missiles/R-3S.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-3S - AAM, IR guided -year: 1962 -fallback: RS2US - AAM, beam-rider -clsids: - - "{R-3S}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-40R.yaml b/resources/weapons/a2a-missiles/R-40R.yaml deleted file mode 100644 index cd0a50992..000000000 --- a/resources/weapons/a2a-missiles/R-40R.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-40R -year: 1971 -fallback: R-3R - AAM, radar guided -clsids: - - "{4EDBA993-2E34-444C-95FB-549300BF7CAF}" diff --git a/resources/weapons/a2a-missiles/R-40T.yaml b/resources/weapons/a2a-missiles/R-40T.yaml deleted file mode 100644 index cd9fc6b44..000000000 --- a/resources/weapons/a2a-missiles/R-40T.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-40T -year: 1983 -fallback: R-40R -clsids: - - "{5F26DBC2-FB43-4153-92DE-6BBCE26CB0FF}" diff --git a/resources/weapons/a2a-missiles/R-55.yaml b/resources/weapons/a2a-missiles/R-55.yaml deleted file mode 100644 index a02a1447b..000000000 --- a/resources/weapons/a2a-missiles/R-55.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-55 - AAM, IR guided -year: 1967 -fallback: R-3S - AAM, IR guided -clsids: - - "{R-55}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-60-2X.yaml b/resources/weapons/a2a-missiles/R-60-2X.yaml deleted file mode 100644 index c5d84ab84..000000000 --- a/resources/weapons/a2a-missiles/R-60-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: R-60 x 2 -year: 1973 -fallback: R-60M -clsids: - - "{R-60 2L}" - - "{R-60 2R}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-60.yaml b/resources/weapons/a2a-missiles/R-60.yaml deleted file mode 100644 index ddc44d24a..000000000 --- a/resources/weapons/a2a-missiles/R-60.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: R-60 -year: 1973 -fallback: R-55 - AAM, IR guided -clsids: - - "{R-60}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-60M-2X.yaml b/resources/weapons/a2a-missiles/R-60M-2X.yaml deleted file mode 100644 index 4a0c65dab..000000000 --- a/resources/weapons/a2a-missiles/R-60M-2X.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: R-60M x 2 -year: 1982 -fallback: R-60 x 2 -clsids: - - "{B0DBC591-0F52-4F7D-AD7B-51E67725FB81}" - - "{275A2855-4A79-4B2D-B082-91EA2ADF4691}" - - "{R-60M 2L}" - - "{R-60M 2R}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-60M.yaml b/resources/weapons/a2a-missiles/R-60M.yaml deleted file mode 100644 index a24011ec4..000000000 --- a/resources/weapons/a2a-missiles/R-60M.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: R-60M -year: 1982 -fallback: R-60 -clsids: - - "{APU-60-1_R_60M}" - - "{R-60M}" - - "{682A481F-0CB5-4693-A382-D00DD4A156D7}" diff --git a/resources/weapons/a2a-missiles/R-73.yaml b/resources/weapons/a2a-missiles/R-73.yaml deleted file mode 100644 index 067543132..000000000 --- a/resources/weapons/a2a-missiles/R-73.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: R-73 (AA-11 Archer) - Infra Red -year: 1984 -fallback: R-60M x 2 -clsids: - - "{FBC29BFE-3D24-4C64-B81D-941239D12249}" - - "{CBC29BFE-3D24-4C64-B81D-941239D12249}" \ No newline at end of file diff --git a/resources/weapons/a2a-missiles/R-77.yaml b/resources/weapons/a2a-missiles/R-77.yaml deleted file mode 100644 index 13eb30748..000000000 --- a/resources/weapons/a2a-missiles/R-77.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: R-77 -year: 2002 -fallback: R-27ER -clsids: - - "{B4C01D60-A8A3-4237-BD72-CA7655BC0FE9}" - - "{B4C01D60-A8A3-4237-BD72-CA7655BC0FEC}" diff --git a/resources/weapons/a2a-missiles/RS2US.yaml b/resources/weapons/a2a-missiles/RS2US.yaml deleted file mode 100644 index 6fd99d0c6..000000000 --- a/resources/weapons/a2a-missiles/RS2US.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: RS2US - AAM, beam-rider -year: 1957 -clsids: - - "{RS-2US}" diff --git a/resources/weapons/bombs/CBU-103-2X.yaml b/resources/weapons/bombs/CBU-103-2X.yaml deleted file mode 100644 index 6ed7efeb6..000000000 --- a/resources/weapons/bombs/CBU-103-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xCBU-103 -year: 2001 -fallback: CBU-103 -clsids: - - "{BRU57_2*CBU-103}" diff --git a/resources/weapons/bombs/CBU-103.yaml b/resources/weapons/bombs/CBU-103.yaml deleted file mode 100644 index 341f55a90..000000000 --- a/resources/weapons/bombs/CBU-103.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: CBU-103 -year: 2001 -fallback: CBU-87 -clsids: - - "{CBU_103}" diff --git a/resources/weapons/bombs/CBU-105-2X.yaml b/resources/weapons/bombs/CBU-105-2X.yaml deleted file mode 100644 index 206b1f341..000000000 --- a/resources/weapons/bombs/CBU-105-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xCBU-105 -year: 2001 -fallback: CBU-105 -clsids: - - "{BRU57_2*CBU-105}" diff --git a/resources/weapons/bombs/CBU-105.yaml b/resources/weapons/bombs/CBU-105.yaml deleted file mode 100644 index 74875ec11..000000000 --- a/resources/weapons/bombs/CBU-105.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: CBU-105 -year: 2001 -fallback: CBU-97 -clsids: - - "{CBU_105}" diff --git a/resources/weapons/bombs/CBU-87-10X.yaml b/resources/weapons/bombs/CBU-87-10X.yaml deleted file mode 100644 index 70a8c7c25..000000000 --- a/resources/weapons/bombs/CBU-87-10X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 10xCBU-87 -year: 1986 -fallback: 28xMk 82 -clsids: - - "CBU87*10" diff --git a/resources/weapons/bombs/CBU-87-2X.yaml b/resources/weapons/bombs/CBU-87-2X.yaml deleted file mode 100644 index 7bfc28408..000000000 --- a/resources/weapons/bombs/CBU-87-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xCBU-87 -year: 1986 -fallback: 2xMk 82 -clsids: - - "{TER_9A_2L*CBU-87}" - - "{TER_9A_2R*CBU-87}" diff --git a/resources/weapons/bombs/CBU-87-3X.yaml b/resources/weapons/bombs/CBU-87-3X.yaml deleted file mode 100644 index 34fab5c3b..000000000 --- a/resources/weapons/bombs/CBU-87-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xCBU-87 -year: 1986 -fallback: 3xMk 82 -clsids: - - "{TER_9A_3*CBU-87}" diff --git a/resources/weapons/bombs/CBU-87.yaml b/resources/weapons/bombs/CBU-87.yaml deleted file mode 100644 index 1f7257dc5..000000000 --- a/resources/weapons/bombs/CBU-87.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: CBU-87 -year: 1986 -fallback: Mk 82 -clsids: - - "{CBU-87}" diff --git a/resources/weapons/bombs/CBU-97-10X.yaml b/resources/weapons/bombs/CBU-97-10X.yaml deleted file mode 100644 index 57ecb0995..000000000 --- a/resources/weapons/bombs/CBU-97-10X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 10xCBU-97 -year: 1992 -fallback: 10xCBU-87 -clsids: - - "CBU97*10" diff --git a/resources/weapons/bombs/CBU-97-2X.yaml b/resources/weapons/bombs/CBU-97-2X.yaml deleted file mode 100644 index a50191103..000000000 --- a/resources/weapons/bombs/CBU-97-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xCBU-97 -year: 1992 -fallback: 2xCBU-87 -clsids: - - "{TER_9A_2L*CBU-97}" - - "{TER_9A_2R*CBU-97}" diff --git a/resources/weapons/bombs/CBU-97-3X.yaml b/resources/weapons/bombs/CBU-97-3X.yaml deleted file mode 100644 index 35aac1dd6..000000000 --- a/resources/weapons/bombs/CBU-97-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xCBU-97 -year: 1992 -fallback: 3xCBU-87 -clsids: - - "{TER_9A_3*CBU-97}" diff --git a/resources/weapons/bombs/CBU-97.yaml b/resources/weapons/bombs/CBU-97.yaml deleted file mode 100644 index 57527755c..000000000 --- a/resources/weapons/bombs/CBU-97.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: CBU-97 -year: 1992 -fallback: CBU-87 -clsids: - - "{5335D97A-35A5-4643-9D9B-026C75961E52}" diff --git a/resources/weapons/bombs/FAB-1500 M54.yaml b/resources/weapons/bombs/FAB-1500 M54.yaml deleted file mode 100644 index 0abe02702..000000000 --- a/resources/weapons/bombs/FAB-1500 M54.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: FAB-1500 M54 -year: 1954 -fallback: FAB-500 M62 -clsids: - - "{40AA4ABE-D6EB-4CD6-AEFE-A1A0477B24AB}" diff --git a/resources/weapons/bombs/FAB-250 M62.yaml b/resources/weapons/bombs/FAB-250 M62.yaml deleted file mode 100644 index d99bd2dd6..000000000 --- a/resources/weapons/bombs/FAB-250 M62.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: FAB-250 M62 -clsids: - - "{FAB_250_M62}" diff --git a/resources/weapons/bombs/FAB-500 M62.yaml b/resources/weapons/bombs/FAB-500 M62.yaml deleted file mode 100644 index cd2d57792..000000000 --- a/resources/weapons/bombs/FAB-500 M62.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: FAB-500 M62 -year: 1962 -fallback: FAB-250 M62 -clsids: - - "{37DCC01E-9E02-432F-B61D-10C166CA2798}" diff --git a/resources/weapons/bombs/GBU-10-2X.yaml b/resources/weapons/bombs/GBU-10-2X.yaml deleted file mode 100644 index c0c513459..000000000 --- a/resources/weapons/bombs/GBU-10-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xGBU-10 -type: LGB -year: 1976 -fallback: 2xMk 84 -clsids: - - "{62BE78B1-9258-48AE-B882-279534C0D278}" diff --git a/resources/weapons/bombs/GBU-10.yaml b/resources/weapons/bombs/GBU-10.yaml deleted file mode 100644 index 4b7306d12..000000000 --- a/resources/weapons/bombs/GBU-10.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: GBU-10 -type: LGB -year: 1976 -fallback: Mk 84 -clsids: - - "DIS_GBU_10" - - "{BRU-32 GBU-10}" - - "{51F9AAE5-964F-4D21-83FB-502E3BFE5F8A}" diff --git a/resources/weapons/bombs/GBU-12-2X.yaml b/resources/weapons/bombs/GBU-12-2X.yaml deleted file mode 100644 index 2cd83f896..000000000 --- a/resources/weapons/bombs/GBU-12-2X.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: 2xGBU-12 -type: LGB -year: 1976 -fallback: 2xMk 82 -clsids: - - "{M2KC_RAFAUT_GBU12}" - - "{BRU33_2X_GBU-12}" - - "DIS_GBU_12_DUAL_GDJ_II19_L" - - "DIS_GBU_12_DUAL_GDJ_II19_R" - - "{TER_9A_2L*GBU-12}" - - "{TER_9A_2R*GBU-12}" - - "{89D000B0-0360-461A-AD83-FB727E2ABA98}" - - "{BRU-42_2xGBU-12_right}" - - "{BRU-42_2*GBU-12_LEFT}" - - "{BRU-42_2*GBU-12_RIGHT}" diff --git a/resources/weapons/bombs/GBU-12-3X.yaml b/resources/weapons/bombs/GBU-12-3X.yaml deleted file mode 100644 index 11ebbedfc..000000000 --- a/resources/weapons/bombs/GBU-12-3X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 3xGBU-12 -type: LGB -year: 1976 -fallback: 3xMk 82 -clsids: - - "BRU-42_3*GBU-12" diff --git a/resources/weapons/bombs/GBU-12.yaml b/resources/weapons/bombs/GBU-12.yaml deleted file mode 100644 index 85705c795..000000000 --- a/resources/weapons/bombs/GBU-12.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: GBU-12 -type: LGB -year: 1976 -fallback: Mk 82 -clsids: - - "DIS_GBU_12" - - "{BRU-32 GBU-12}" - - "{DB769D48-67D7-42ED-A2BE-108D566C8B1E}" diff --git a/resources/weapons/bombs/GBU-16-2X.yaml b/resources/weapons/bombs/GBU-16-2X.yaml deleted file mode 100644 index 19afd987f..000000000 --- a/resources/weapons/bombs/GBU-16-2X.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: 2xGBU-16 -type: LGB -year: 1976 -fallback: 2xMk 83 -clsids: - - "{BRU33_2X_GBU-16}" - - "{BRU-42_2*GBU-16_LEFT}" - - "{BRU-42_2*GBU-16_RIGHT}" diff --git a/resources/weapons/bombs/GBU-16.yaml b/resources/weapons/bombs/GBU-16.yaml deleted file mode 100644 index c966af608..000000000 --- a/resources/weapons/bombs/GBU-16.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: GBU-16 -type: LGB -year: 1976 -fallback: Mk 83 -clsids: - - "DIS_GBU_16" - - "{BRU-32 GBU-16}" - - "{0D33DDAE-524F-4A4E-B5B8-621754FE3ADE}" diff --git a/resources/weapons/bombs/GBU-24.yaml b/resources/weapons/bombs/GBU-24.yaml deleted file mode 100644 index 6258584f5..000000000 --- a/resources/weapons/bombs/GBU-24.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: GBU-24 -type: LGB -year: 1986 -fallback: GBU-10 -clsids: - - "{BRU-32 GBU-24}" - - "{34759BBC-AF1E-4AEE-A581-498FF7A6EBCE}" - - "{GBU-24}" diff --git a/resources/weapons/bombs/GBU-27.yaml b/resources/weapons/bombs/GBU-27.yaml deleted file mode 100644 index 069ad6dd0..000000000 --- a/resources/weapons/bombs/GBU-27.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: GBU-27 -type: LGB -year: 1987 -fallback: GBU-10 -clsids: - - "{EB969276-1922-4ED1-A5CB-18590F45D7FE}" - - "{EF0A9419-01D6-473B-99A3-BEBDB923B14D}" - - "{B8C99F40-E486-4040-B547-6639172A5D57}" diff --git a/resources/weapons/bombs/GBU-31V1B-8X.yaml b/resources/weapons/bombs/GBU-31V1B-8X.yaml deleted file mode 100644 index ea968dd76..000000000 --- a/resources/weapons/bombs/GBU-31V1B-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 8xGBU-31(V)1/B -year: 2001 -fallback: 8xMk 84 -clsids: - - "GBU-31*8" diff --git a/resources/weapons/bombs/GBU-31V1B.yaml b/resources/weapons/bombs/GBU-31V1B.yaml deleted file mode 100644 index b08b3f34a..000000000 --- a/resources/weapons/bombs/GBU-31V1B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-31(V)1/B -year: 2001 -fallback: GBU-24 -clsids: - - "{GBU-31}" diff --git a/resources/weapons/bombs/GBU-31V2B.yaml b/resources/weapons/bombs/GBU-31V2B.yaml deleted file mode 100644 index a8a55030a..000000000 --- a/resources/weapons/bombs/GBU-31V2B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-31(V)2/B -year: 2001 -fallback: GBU-24 -clsids: - - "{GBU_31_V_2B}" diff --git a/resources/weapons/bombs/GBU-31V3B-8X.yaml b/resources/weapons/bombs/GBU-31V3B-8X.yaml deleted file mode 100644 index 33639184b..000000000 --- a/resources/weapons/bombs/GBU-31V3B-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 8xGBU-31(V)3/B -year: 2001 -fallback: 8xGBU-31(V)1/B -clsids: - - "GBU-31V3B*8" diff --git a/resources/weapons/bombs/GBU-31V3B.yaml b/resources/weapons/bombs/GBU-31V3B.yaml deleted file mode 100644 index 0f4e08431..000000000 --- a/resources/weapons/bombs/GBU-31V3B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-31(V)3/B -year: 2001 -fallback: GBU-24 -clsids: - - "{GBU-31V3B}" diff --git a/resources/weapons/bombs/GBU-31V4B.yaml b/resources/weapons/bombs/GBU-31V4B.yaml deleted file mode 100644 index 04b6298aa..000000000 --- a/resources/weapons/bombs/GBU-31V4B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-31(V)4/B -year: 2001 -fallback: GBU-24 -clsids: - - "{GBU_31_V_4B}" diff --git a/resources/weapons/bombs/GBU-32V2B.yaml b/resources/weapons/bombs/GBU-32V2B.yaml deleted file mode 100644 index 0f65cf5ee..000000000 --- a/resources/weapons/bombs/GBU-32V2B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-32(V)2/B -year: 2002 -fallback: GBU-16 -clsids: - - "{GBU_32_V_2B}" diff --git a/resources/weapons/bombs/GBU-38-16X.yaml b/resources/weapons/bombs/GBU-38-16X.yaml deleted file mode 100644 index ce61d450d..000000000 --- a/resources/weapons/bombs/GBU-38-16X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 16xGBU-38 -year: 2002 -fallback: 8xGBU-31(V)1/B -clsids: - - "GBU-38*16" diff --git a/resources/weapons/bombs/GBU-38-2X.yaml b/resources/weapons/bombs/GBU-38-2X.yaml deleted file mode 100644 index 48f0ac39c..000000000 --- a/resources/weapons/bombs/GBU-38-2X.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: 2xGBU-38 -year: 2002 -fallback: 2xGBU-12 -clsids: - - "{BRU55_2*GBU-38}" - - "{BRU57_2*GBU-38}" - - "{BRU-42_2*GBU-38_LEFT}" - - "{BRU-42_2*GBU-38_RIGHT}" diff --git a/resources/weapons/bombs/GBU-38-3X.yaml b/resources/weapons/bombs/GBU-38-3X.yaml deleted file mode 100644 index 72763726e..000000000 --- a/resources/weapons/bombs/GBU-38-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xGBU-38 -year: 2002 -fallback: 3xGBU-12 -clsids: - - "{BRU-42_3*GBU-38}" diff --git a/resources/weapons/bombs/GBU-38.yaml b/resources/weapons/bombs/GBU-38.yaml deleted file mode 100644 index b02f2332c..000000000 --- a/resources/weapons/bombs/GBU-38.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-38 -year: 2002 -fallback: GBU-12 -clsids: - - "{GBU-38}" diff --git a/resources/weapons/bombs/GBU-54B-2X.yaml b/resources/weapons/bombs/GBU-54B-2X.yaml deleted file mode 100644 index ec4b5dd4e..000000000 --- a/resources/weapons/bombs/GBU-54B-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xGBU-54B -year: 2012 -fallback: 2xGBU-38 -clsids: - - "{BRU-70A_2*GBU-54_RIGHT}" - - "{BRU-70A_2*GBU-54_LEFT}" diff --git a/resources/weapons/bombs/GBU-54B-3X.yaml b/resources/weapons/bombs/GBU-54B-3X.yaml deleted file mode 100644 index ed4a40560..000000000 --- a/resources/weapons/bombs/GBU-54B-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xGBU-54B -year: 2012 -fallback: 3xGBU-38 -clsids: - - "{BRU-70A_3*GBU-54}" diff --git a/resources/weapons/bombs/GBU-54B.yaml b/resources/weapons/bombs/GBU-54B.yaml deleted file mode 100644 index 67e024cf7..000000000 --- a/resources/weapons/bombs/GBU-54B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: GBU-54B -year: 2012 -fallback: GBU-38 -clsids: - - "{GBU_54_V_1B}" diff --git a/resources/weapons/bombs/KAB-1500KR.yaml b/resources/weapons/bombs/KAB-1500KR.yaml deleted file mode 100644 index 12613762c..000000000 --- a/resources/weapons/bombs/KAB-1500KR.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-1500KR -year: 1995 -fallback: FAB-1500 M54 -clsids: - - "{KAB_1500Kr_LOADOUT}" diff --git a/resources/weapons/bombs/KAB-1500L.yaml b/resources/weapons/bombs/KAB-1500L.yaml deleted file mode 100644 index a69479087..000000000 --- a/resources/weapons/bombs/KAB-1500L.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-1500L -year: 1995 -fallback: KAB-1500KR -clsids: - - "{39821727-F6E2-45B3-B1F0-490CC8921D1E}" diff --git a/resources/weapons/bombs/KAB-1500LG-Pr.yaml b/resources/weapons/bombs/KAB-1500LG-Pr.yaml deleted file mode 100644 index 7aae49301..000000000 --- a/resources/weapons/bombs/KAB-1500LG-Pr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-1500LG-Pr -year: 2000 -fallback: KAB-1500L -clsids: - - "{KAB_1500LG_LOADOUT}" diff --git a/resources/weapons/bombs/KAB-500Kr.yaml b/resources/weapons/bombs/KAB-500Kr.yaml deleted file mode 100644 index 97678556e..000000000 --- a/resources/weapons/bombs/KAB-500Kr.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-500Kr -year: 1975 -fallback: FAB-500 M62 -clsids: - - "{E2C426E3-8B10-4E09-B733-9CDC26520F48}" diff --git a/resources/weapons/bombs/KAB-500LG.yaml b/resources/weapons/bombs/KAB-500LG.yaml deleted file mode 100644 index fef61d7a5..000000000 --- a/resources/weapons/bombs/KAB-500LG.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-500LG -year: 1975 -fallback: KAB-500Kr -clsids: - - "{BA565F89-2373-4A84-9502-A0E017D3A44A}" diff --git a/resources/weapons/bombs/KAB-500S.yaml b/resources/weapons/bombs/KAB-500S.yaml deleted file mode 100644 index 6e45ccd4b..000000000 --- a/resources/weapons/bombs/KAB-500S.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KAB-500S -year: 2007 -fallback: KAB-500LG -clsids: - - "{KAB_500S_LOADOUT}" diff --git a/resources/weapons/bombs/Mk-82-12X.yaml b/resources/weapons/bombs/Mk-82-12X.yaml deleted file mode 100644 index eb001d7a3..000000000 --- a/resources/weapons/bombs/Mk-82-12X.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: 12xMk 82 -clsids: - - "{585D626E-7F42-4073-AB70-41E728C333E2}" diff --git a/resources/weapons/bombs/Mk-82-27X.yaml b/resources/weapons/bombs/Mk-82-27X.yaml deleted file mode 100644 index 07b5cb69c..000000000 --- a/resources/weapons/bombs/Mk-82-27X.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: 27xMk 82 -fallback: 12xMk 82 -clsids: - - "{6C47D097-83FF-4FB2-9496-EAB36DDF0B05}" diff --git a/resources/weapons/bombs/Mk-82-28X.yaml b/resources/weapons/bombs/Mk-82-28X.yaml deleted file mode 100644 index 779972160..000000000 --- a/resources/weapons/bombs/Mk-82-28X.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: 28xMk 82 -clsids: - - "MK_82*28" diff --git a/resources/weapons/bombs/Mk-82-2X.yaml b/resources/weapons/bombs/Mk-82-2X.yaml deleted file mode 100644 index 3a3d7ea7c..000000000 --- a/resources/weapons/bombs/Mk-82-2X.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: 2xMk 82 -fallback: Mk 82 -clsids: - - "{M2KC_RAFAUT_MK82}" - - "{BRU33_2X_MK-82}" - - "DIS_MK_82_DUAL_GDJ_II19_L" - - "DIS_MK_82_DUAL_GDJ_II19_R" - - "{D5D51E24-348C-4702-96AF-97A714E72697}" - - "{TER_9A_2L*MK-82}" - - "{TER_9A_2R*MK-82}" - - "{BRU-42_2*Mk-82_LEFT}" - - "{BRU-42_2*Mk-82_RIGHT}" - - "{BRU42_2*MK82 RS}" - - "{BRU3242_2*MK82 RS}" - - "{PHXBRU3242_2*MK82 RS}" - - "{BRU42_2*MK82 LS}" - - "{BRU3242_2*MK82 LS}" - - "{PHXBRU3242_2*MK82 LS}" diff --git a/resources/weapons/bombs/Mk-82-3X.yaml b/resources/weapons/bombs/Mk-82-3X.yaml deleted file mode 100644 index f9e691ba5..000000000 --- a/resources/weapons/bombs/Mk-82-3X.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: 3xMk 82 -fallback: 2xMk 82 -clsids: - - "{60CC734F-0AFA-4E2E-82B8-93B941AB11CF}" diff --git a/resources/weapons/bombs/Mk-82.yaml b/resources/weapons/bombs/Mk-82.yaml deleted file mode 100644 index 70733a5b8..000000000 --- a/resources/weapons/bombs/Mk-82.yaml +++ /dev/null @@ -1,11 +0,0 @@ -name: Mk 82 -clsids: - - "{BRU-32 MK-82}" - - "{Mk_82B}" - - "{Mk_82BT}" - - "{Mk_82P}" - - "{Mk_82PT}" - - "{Mk_82SB}" - - "{Mk_82SP}" - - "{Mk_82YT}" - - "{BCE4E030-38E9-423E-98ED-24BE3DA87C32}" diff --git a/resources/weapons/bombs/Mk-83-2X.yaml b/resources/weapons/bombs/Mk-83-2X.yaml deleted file mode 100644 index 4d2876ad4..000000000 --- a/resources/weapons/bombs/Mk-83-2X.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: 2xMk 83 -fallback: Mk 83 -clsids: - - "{BRU33_2X_MK-83}" - - "{18617C93-78E7-4359-A8CE-D754103EDF63}" - - "{BRU-42_2*Mk-83_LEFT}" - - "{BRU-42_2*Mk-83_RIGHT}" diff --git a/resources/weapons/bombs/Mk-83.yaml b/resources/weapons/bombs/Mk-83.yaml deleted file mode 100644 index 42450ce7f..000000000 --- a/resources/weapons/bombs/Mk-83.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: Mk 83 -fallback: 2xMk 82 -clsids: - - "{MAK79_MK83 1R}" - - "{MAK79_MK83 1L}" - - "{BRU-32 MK-83}" - - "{Mk_83BT}" - - "{Mk_83CT}" - - "{Mk_83P}" - - "{Mk_83PT}" - - "{BRU42_MK83 RS}" - - "{BRU3242_MK83 RS}" - - "{PHXBRU3242_MK83 RS}" - - "{7A44FF09-527C-4B7E-B42B-3F111CFE50FB}" - - "{BRU42_MK83 LS}" - - "{BRU3242_MK83 LS}" - - "{PHXBRU3242_MK83 LS}" diff --git a/resources/weapons/bombs/Mk-84-8X.yaml b/resources/weapons/bombs/Mk-84-8X.yaml deleted file mode 100644 index fae5102f5..000000000 --- a/resources/weapons/bombs/Mk-84-8X.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: 8xMk 84 -clsids: - - "B-1B_Mk-84*8" diff --git a/resources/weapons/bombs/Mk-84.yaml b/resources/weapons/bombs/Mk-84.yaml deleted file mode 100644 index 104d2e6b3..000000000 --- a/resources/weapons/bombs/Mk-84.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: Mk 84 -fallback: 2xMk 83 -clsids: - - "{AB8B8299-F1CC-4359-89B5-2172E0CF4A5A}" - - "{BRU-32 MK-84}" - - "{Mk_84P}" - - "{Mk_84T}" diff --git a/resources/weapons/pods/OH-58D_Brauning.yaml b/resources/weapons/pods/OH-58D_Brauning.yaml deleted file mode 100644 index 72f6fb000..000000000 --- a/resources/weapons/pods/OH-58D_Brauning.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: Brauning Gun Pod -fallback: M261 - 19 x UnGd Rkts, 70 mm Hydra 70 M151 HE -clsids: - - "oh-58-brauning" diff --git a/resources/weapons/pods/alq-131.yaml b/resources/weapons/pods/alq-131.yaml deleted file mode 100644 index 15edd820b..000000000 --- a/resources/weapons/pods/alq-131.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AN/ALQ-131 ECM -# Hard to find information on initial iteration - 74 military budget mentions development, FAS.org suggests late 70s, and DCS usage is allowed on or after 1973 -year: 1977 -fallback: 2xAIM-120C -clsids: - - "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}" diff --git a/resources/weapons/pods/alq-184 Long.yaml b/resources/weapons/pods/alq-184 Long.yaml deleted file mode 100644 index 1a9c2103e..000000000 --- a/resources/weapons/pods/alq-184 Long.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AN/ALQ-184 Long ECM -# https://www.deagel.com/Protection%20Systems/ANALQ-184/a001666 -year: 1987 -fallback: AN/ALQ-184 ECM -clsids: - - "ALQ_184_Long" diff --git a/resources/weapons/pods/alq-184.yaml b/resources/weapons/pods/alq-184.yaml deleted file mode 100644 index 587298080..000000000 --- a/resources/weapons/pods/alq-184.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AN/ALQ-184 ECM -# https://www.deagel.com/Protection%20Systems/ANALQ-184/a001666 -year: 1987 -fallback: AN/ALQ-131 ECM -clsids: - - "ALQ_184" diff --git a/resources/weapons/pods/atflir.yaml b/resources/weapons/pods/atflir.yaml deleted file mode 100644 index a33ee9cad..000000000 --- a/resources/weapons/pods/atflir.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AN/ASQ-228 ATFLIR -type: TGP -year: 2003 -# A bit of a hack, but fixes the common case where the Hornet cheek station is -# empty because no TGP is available. -fallback: AIM-120C -clsids: - - "{AN_ASQ_228}" diff --git a/resources/weapons/pods/hts.yaml b/resources/weapons/pods/hts.yaml deleted file mode 100644 index d39a66287..000000000 --- a/resources/weapons/pods/hts.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AN/ASQ-213 HARM Targeting System -# https://www.af.mil/About-Us/Fact-Sheets/Display/Article/104602/high-speed-anti-radiation-missile-targeting-system/ -# We have the R7 pod, but since we never get older variants of things in DCS -# just pretend it's as old as the initial revision. -year: 1994 -clsids: - - "{AN_ASQ_213}" diff --git a/resources/weapons/pods/lantirn.yaml b/resources/weapons/pods/lantirn.yaml deleted file mode 100644 index 774bc0702..000000000 --- a/resources/weapons/pods/lantirn.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: AN/AAQ-14 LANTIRN -type: TGP -year: 1990 -clsids: - - "{F14-LANTIRN-TP}" - - "{CAAC1CFD-6745-416B-AFA4-CB57414856D0}" - - "{D1744B93-2A8A-4C4D-B004-7A09CD8C8F3F}" - - "{F-15E_AAQ-14_LANTIRN}" diff --git a/resources/weapons/pods/litening.yaml b/resources/weapons/pods/litening.yaml deleted file mode 100644 index 4bee3ed6b..000000000 --- a/resources/weapons/pods/litening.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: AN/AAQ-28 LITENING -type: TGP -year: 1999 -# A bit of a hack, but fixes the common case where the Hornet cheek station is -# empty because no TGP is available. For the Viper this will have no effect -# because missiles can't be put on that station, but for the Viper an empty -# pylon is the correct replacement for a TGP anyway (the jammer goes on the -# other fuselage station, HTS isn't a good replacement, and we don't have -# LANTIRN for the Viper). -# -# For the A-10 an empty pylon is also fine. -fallback: AIM-120C -clsids: - - "{A111396E-D3E8-4b9c-8AC9-2432489304D5}" - - "{AAQ-28_LEFT}" diff --git a/resources/weapons/rockets/AGR-20 M282.yaml b/resources/weapons/rockets/AGR-20 M282.yaml deleted file mode 100644 index 5af90f3d9..000000000 --- a/resources/weapons/rockets/AGR-20 M282.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: LAU-131 7xMPP APKWS -year: 2012 -fallback: AGM-65E2/L -clsids: - - "{LAU-131 - 7 AGR-20 M282}" diff --git a/resources/weapons/rockets/AGR-20A.yaml b/resources/weapons/rockets/AGR-20A.yaml deleted file mode 100644 index a0bcf81ad..000000000 --- a/resources/weapons/rockets/AGR-20A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: LAU-131 7xHE APKWS -year: 2012 -fallback: AGM-65E2/L -clsids: - - "{LAU-131 - 7 AGR-20A}" diff --git a/resources/weapons/rockets/LAU-61 M151.yaml b/resources/weapons/rockets/LAU-61 M151.yaml deleted file mode 100644 index bcf0eb676..000000000 --- a/resources/weapons/rockets/LAU-61 M151.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: LAU-61 pod - 19 x 2.75\" Hydra, UnGd Rkts M151, HE -clsids: - - "{FD90A1DC-9147-49FA-BF56-CB83EF0BD32B}" diff --git a/resources/weapons/rockets/M260 Mk5 HEAT.yaml b/resources/weapons/rockets/M260 Mk5 HEAT.yaml deleted file mode 100644 index 81feade0f..000000000 --- a/resources/weapons/rockets/M260 Mk5 HEAT.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: M260 pod - 7 x 2.75\" Hydra, UnGd Rkts Mk5, HEAT -fallback: LAU-61 pod - 19 x 2.75\" Hydra, UnGd Rkts M151, HE -clsids: - - "M260_HYDRA" diff --git a/resources/weapons/rockets/M261 MK151.yaml b/resources/weapons/rockets/M261 MK151.yaml deleted file mode 100644 index 2e8cf35d9..000000000 --- a/resources/weapons/rockets/M261 MK151.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: M261 - 19 x UnGd Rkts, 70 mm Hydra 70 M151 HE -fallback: M260 pod - 7 x 2.75\" Hydra, UnGd Rkts Mk5, HEAT -clsids: - - "M261_MK151" diff --git a/resources/weapons/rockets/S-24A.yaml b/resources/weapons/rockets/S-24A.yaml deleted file mode 100644 index c355b8b03..000000000 --- a/resources/weapons/rockets/S-24A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: S-24A -year: 1960 -fallback: FAB-500 M62 -clsids: - - "{S-24A}" diff --git a/resources/weapons/rockets/S-24B.yaml b/resources/weapons/rockets/S-24B.yaml deleted file mode 100644 index 4726cfe21..000000000 --- a/resources/weapons/rockets/S-24B.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: S-24B -year: 1975 -fallback: S-24A -clsids: - - "{3858707D-F5D5-4bbb-BDD8-ABB0530EBC7C}" - - "{1FA14DEA-8CDB-45AD-88A8-EC068DF1E65A}" - - "{S-24B}" diff --git a/resources/weapons/rockets/S-25O.yaml b/resources/weapons/rockets/S-25O.yaml deleted file mode 100644 index 19376b777..000000000 --- a/resources/weapons/rockets/S-25O.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: S-25O -year: 1975 -# May have been IOC in 1975 per Weapon systems.net, but not widely used till the 80s or 90s per Deagal. Deagal says IOC 88 -fallback: S-24B -clsids: - - "{S_25_O}" diff --git a/resources/weapons/rockets/S-25OFM.yaml b/resources/weapons/rockets/S-25OFM.yaml deleted file mode 100644 index 9a13daf30..000000000 --- a/resources/weapons/rockets/S-25OFM.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: S-25OFM -year: 1978 -# May have been IOC in late 70's per WeaponSystems.net. Deagal says base S-25 didn't IOC 88 so not sure -fallback: S-25O -clsids: - - "{A0648264-4BC0-4EE8-A543-D119F6BA4257}" diff --git a/resources/weapons/standoff/ADM-141A.yaml b/resources/weapons/standoff/ADM-141A.yaml deleted file mode 100644 index 6b55a6941..000000000 --- a/resources/weapons/standoff/ADM-141A.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: ADM-141A TALD -# https://www.designation-systems.net/dusrm/m-141.html -year: 1987 -type: decoy -clsids: - - "{BRU42_ADM141}" - - "{BRU3242_ADM141}" - - "{ADM_141A}" - - "{ADM_141B}" - - "{BRU_42A_x1_ADM_141A}" - - "{BRU_42A_x2_ADM_141A}" - - "{BRU_42A_x3_ADM_141A}" diff --git a/resources/weapons/standoff/AGM-114K-1X.yaml b/resources/weapons/standoff/AGM-114K-1X.yaml deleted file mode 100644 index 5a8da1a44..000000000 --- a/resources/weapons/standoff/AGM-114K-1X.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AGM-114K * 1 -year: 1993 -fallback: 4 x BGM-71D TOW ATGM -clsids: - - "{M299_1xAGM_114K_OUTBOARD_PORT}" - - "{M299_1xAGM_114K_OUTBOARD_STARBOARD}" - - "{ee368869-c35a-486a-afe7-284beb7c5d52}" diff --git a/resources/weapons/standoff/AGM-114K-2X.yaml b/resources/weapons/standoff/AGM-114K-2X.yaml deleted file mode 100644 index 02aad0e1e..000000000 --- a/resources/weapons/standoff/AGM-114K-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-114K * 2 -year: 1993 -fallback: 4 x BGM-71D TOW ATGM -clsids: - - "{M299_2xAGM_114K}" - - "AGM114x2_OH_58" diff --git a/resources/weapons/standoff/AGM-114K-3X.yaml b/resources/weapons/standoff/AGM-114K-3X.yaml deleted file mode 100644 index 9955daf53..000000000 --- a/resources/weapons/standoff/AGM-114K-3X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-114K * 3 -year: 1993 -fallback: 4 x BGM-71D TOW ATGM -clsids: - - "{M299_3xAGM_114K_OUTBOARD_PORT}" - - "{M299_3xAGM_114K_OUTBOARD_STARBOARD}" diff --git a/resources/weapons/standoff/AGM-114K-4X.yaml b/resources/weapons/standoff/AGM-114K-4X.yaml deleted file mode 100644 index e03a6334d..000000000 --- a/resources/weapons/standoff/AGM-114K-4X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-114K * 4 -year: 1993 -# AGM-114A IOC in 1983 can be used as a stand in until earlier variants are added to DCS. AGM-114K true IOC is 1993 -fallback: 4 x BGM-71D TOW ATGM -clsids: - - "{88D18A5E-99C8-4B04-B40B-1C02F2018B6E}" diff --git a/resources/weapons/standoff/AGM-114L-1X.yaml b/resources/weapons/standoff/AGM-114L-1X.yaml deleted file mode 100644 index 65b7ad78f..000000000 --- a/resources/weapons/standoff/AGM-114L-1X.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AGM-114L * 1 -year: 2000 -fallback: AGM-114K * 1 -clsids: - - "{M299_1xAGM_114L_OUTBOARD_PORT}" - - "{M299_1xAGM_114L_OUTBOARD_STARBOARD}" - - "{AGM_114L}" diff --git a/resources/weapons/standoff/AGM-114L-2X.yaml b/resources/weapons/standoff/AGM-114L-2X.yaml deleted file mode 100644 index d2ae956bc..000000000 --- a/resources/weapons/standoff/AGM-114L-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-114L * 2 -year: 2000 -fallback: AGM-114K * 2 -clsids: - - "{M299_2xAGM_114L}" diff --git a/resources/weapons/standoff/AGM-114L-3X.yaml b/resources/weapons/standoff/AGM-114L-3X.yaml deleted file mode 100644 index f71617648..000000000 --- a/resources/weapons/standoff/AGM-114L-3X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-114L * 3 -year: 2000 -fallback: AGM-114K * 3 -clsids: - - "{M299_3xAGM_114L_OUTBOARD_PORT}" - - "{M299_3xAGM_114L_OUTBOARD_STARBOARD}" diff --git a/resources/weapons/standoff/AGM-154A-2X.yaml b/resources/weapons/standoff/AGM-154A-2X.yaml deleted file mode 100644 index 539cec69e..000000000 --- a/resources/weapons/standoff/AGM-154A-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAGM-154A JSOW -year: 1998 -fallback: AGM-154C JSOW -clsids: - - "{BRU55_2*AGM-154A}" - - "{BRU57_2*AGM-154A}" diff --git a/resources/weapons/standoff/AGM-154A.yaml b/resources/weapons/standoff/AGM-154A.yaml deleted file mode 100644 index e4d5c6570..000000000 --- a/resources/weapons/standoff/AGM-154A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-154A JSOW -year: 1998 -fallback: AGM-65G -clsids: - - "{AGM-154A}" diff --git a/resources/weapons/standoff/AGM-154C-2X.yaml b/resources/weapons/standoff/AGM-154C-2X.yaml deleted file mode 100644 index d32a20964..000000000 --- a/resources/weapons/standoff/AGM-154C-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 2xAGM-154C JSOW -year: 2005 -fallback: 2xAGM-154A JSOW -clsids: - - "{BRU55_2*AGM-154C}" diff --git a/resources/weapons/standoff/AGM-154C-4X.yaml b/resources/weapons/standoff/AGM-154C-4X.yaml deleted file mode 100644 index 2de6be9fb..000000000 --- a/resources/weapons/standoff/AGM-154C-4X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 4xAGM-154C -year: 2005 -fallback: 8xGBU-31(V)3/B -clsids: - - "{AABA1A14-78A1-4E85-94DD-463CF75BD9E4}" diff --git a/resources/weapons/standoff/AGM-154C.yaml b/resources/weapons/standoff/AGM-154C.yaml deleted file mode 100644 index 74dfaeb7f..000000000 --- a/resources/weapons/standoff/AGM-154C.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-154C JSOW -year: 2005 -fallback: AGM-154A JSOW -clsids: - - "{9BCC2A2B-5708-4860-B1F1-053A18442067}" diff --git a/resources/weapons/standoff/AGM-45A.yaml b/resources/weapons/standoff/AGM-45A.yaml deleted file mode 100644 index abb730a93..000000000 --- a/resources/weapons/standoff/AGM-45A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-45A Shrike ARM -type: ARM -year: 1965 -clsids: - - "{AGM_45A}" diff --git a/resources/weapons/standoff/AGM-45B.yaml b/resources/weapons/standoff/AGM-45B.yaml deleted file mode 100644 index 067630752..000000000 --- a/resources/weapons/standoff/AGM-45B.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-45B Shrike ARM (Imp) -type: ARM -year: 1972 -fallback: AGM-45A Shrike ARM -clsids: - - "{3E6B632D-65EB-44D2-9501-1C2D04515404}" diff --git a/resources/weapons/standoff/AGM-62.yaml b/resources/weapons/standoff/AGM-62.yaml deleted file mode 100644 index d1f72a122..000000000 --- a/resources/weapons/standoff/AGM-62.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-62 Walleye II -year: 1972 -fallback: Mk 84 -clsids: - - "{C40A1E3A-DD05-40D9-85A4-217729E37FAE}" diff --git a/resources/weapons/standoff/AGM-65A.yaml b/resources/weapons/standoff/AGM-65A.yaml deleted file mode 100644 index 78b0e54e4..000000000 --- a/resources/weapons/standoff/AGM-65A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-65A -year: 1972 -fallback: AGM-62 Walleye II -clsids: - - "LAU_117_AGM_65A" diff --git a/resources/weapons/standoff/AGM-65B.yaml b/resources/weapons/standoff/AGM-65B.yaml deleted file mode 100644 index 8a2f59986..000000000 --- a/resources/weapons/standoff/AGM-65B.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-65B -year: 1975 -fallback: AGM-65A -clsids: - - "LAU_117_AGM_65B" diff --git a/resources/weapons/standoff/AGM-65D-2X.yaml b/resources/weapons/standoff/AGM-65D-2X.yaml deleted file mode 100644 index 3911443fb..000000000 --- a/resources/weapons/standoff/AGM-65D-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAGM-65D -year: 1986 -fallback: AGM-65D -clsids: - - "{E6A6262A-CA08-4B3D-B030-E1A993B98452}" - - "{E6A6262A-CA08-4B3D-B030-E1A993B98453}" diff --git a/resources/weapons/standoff/AGM-65D-3X.yaml b/resources/weapons/standoff/AGM-65D-3X.yaml deleted file mode 100644 index e3b261520..000000000 --- a/resources/weapons/standoff/AGM-65D-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xAGM-65D -year: 1986 -fallback: 2xAGM-65D -clsids: - - "{DAC53A2F-79CA-42FF-A77A-F5649B601308}" diff --git a/resources/weapons/standoff/AGM-65D.yaml b/resources/weapons/standoff/AGM-65D.yaml deleted file mode 100644 index 42c11666f..000000000 --- a/resources/weapons/standoff/AGM-65D.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AGM-65D -year: 1986 -fallback: AGM-65B -clsids: - - "{444BA8AE-82A7-4345-842E-76154EFCCA47}" - - "{444BA8AE-82A7-4345-842E-76154EFCCA46}" - - "LAU_88_AGM_65D_ONE" diff --git a/resources/weapons/standoff/AGM-65E-2X.yaml b/resources/weapons/standoff/AGM-65E-2X.yaml deleted file mode 100644 index 85ffafb08..000000000 --- a/resources/weapons/standoff/AGM-65E-2X.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: 2xAGM-65E -type: LGB -year: 1985 -fallback: AGM-65E -clsids: - - "{2CC29C7A-E863-411C-8A6E-BD6F0E730548}" - - "{2CC29C7A-E863-411C-8A6E-BD6F0E730547}" diff --git a/resources/weapons/standoff/AGM-65E-3X.yaml b/resources/weapons/standoff/AGM-65E-3X.yaml deleted file mode 100644 index 4f98940dd..000000000 --- a/resources/weapons/standoff/AGM-65E-3X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 3xAGM-65E -type: LGB -year: 1985 -fallback: 2xAGM-65E -clsids: - - "{71AAB9B8-81C1-4925-BE50-1EF8E9899271}" diff --git a/resources/weapons/standoff/AGM-65E.yaml b/resources/weapons/standoff/AGM-65E.yaml deleted file mode 100644 index d8323eb08..000000000 --- a/resources/weapons/standoff/AGM-65E.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-65E -type: LGB -year: 1985 -fallback: AGM-65G -clsids: - - "{F16A4DE0-116C-4A71-97F0-2CF85B0313EC}" diff --git a/resources/weapons/standoff/AGM-65E2L.yaml b/resources/weapons/standoff/AGM-65E2L.yaml deleted file mode 100644 index 2a785696f..000000000 --- a/resources/weapons/standoff/AGM-65E2L.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AGM-65E2/L -type: LGB -year: 2002 -# USMC Designation is the E2, USAF is the L -fallback: 3xAGM-65E -clsids: - - "LAU_117_AGM_65L" diff --git a/resources/weapons/standoff/AGM-65F.yaml b/resources/weapons/standoff/AGM-65F.yaml deleted file mode 100644 index 35516277e..000000000 --- a/resources/weapons/standoff/AGM-65F.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-65F -year: 1991 -fallback: 3xAGM-65D -clsids: - - "LAU_117_AGM_65F" diff --git a/resources/weapons/standoff/AGM-65G.yaml b/resources/weapons/standoff/AGM-65G.yaml deleted file mode 100644 index 2c2d9d2b3..000000000 --- a/resources/weapons/standoff/AGM-65G.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-65G -year: 1989 -fallback: AGM-65F -clsids: - - "LAU_117_AGM_65G" diff --git a/resources/weapons/standoff/AGM-65H-2X.yaml b/resources/weapons/standoff/AGM-65H-2X.yaml deleted file mode 100644 index 18fb8b6e3..000000000 --- a/resources/weapons/standoff/AGM-65H-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAGM-65H -year: 2002 -fallback: AGM-65H -clsids: - - "LAU_88_AGM_65H_2_L" - - "LAU_88_AGM_65H_2_R" diff --git a/resources/weapons/standoff/AGM-65H-3X.yaml b/resources/weapons/standoff/AGM-65H-3X.yaml deleted file mode 100644 index 41cfb0efa..000000000 --- a/resources/weapons/standoff/AGM-65H-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xAGM-65H -year: 2002 -fallback: 2xAGM-65H -clsids: - - "LAU_88_AGM_65H_3" diff --git a/resources/weapons/standoff/AGM-65H.yaml b/resources/weapons/standoff/AGM-65H.yaml deleted file mode 100644 index a28c7cfe9..000000000 --- a/resources/weapons/standoff/AGM-65H.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-65H -year: 2002 -fallback: 3xAGM-65D -clsids: - - "LAU_117_AGM_65H" - - "LAU_88_AGM_65H" diff --git a/resources/weapons/standoff/AGM-65K-2X.yaml b/resources/weapons/standoff/AGM-65K-2X.yaml deleted file mode 100644 index 8fd15f0f9..000000000 --- a/resources/weapons/standoff/AGM-65K-2X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 2xAGM-65K -year: 2008 -fallback: AGM-65K -clsids: - - "{D7670BC7-881B-4094-906C-73879CF7EB27}" - - "{D7670BC7-881B-4094-906C-73879CF7EB28}" diff --git a/resources/weapons/standoff/AGM-65K-3X.yaml b/resources/weapons/standoff/AGM-65K-3X.yaml deleted file mode 100644 index 591ae95cf..000000000 --- a/resources/weapons/standoff/AGM-65K-3X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 3xAGM-65K -year: 2008 -fallback: 2xAGM-65K -clsids: - - "{907D835F-E650-4154-BAFD-C656882555C0}" diff --git a/resources/weapons/standoff/AGM-65K.yaml b/resources/weapons/standoff/AGM-65K.yaml deleted file mode 100644 index f1c82e7d5..000000000 --- a/resources/weapons/standoff/AGM-65K.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-65K -year: 2008 -fallback: AGM-65G -clsids: - - "{69DC8AE7-8F77-427B-B8AA-B19D3F478B65}" - - "{69DC8AE7-8F77-427B-B8AA-B19D3F478B66}" diff --git a/resources/weapons/standoff/AGM-84A-8X.yaml b/resources/weapons/standoff/AGM-84A-8X.yaml deleted file mode 100644 index 330cdf949..000000000 --- a/resources/weapons/standoff/AGM-84A-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 8xAGM-84A -year: 1979 -fallback: 27xMk 82 -clsids: - - "{46ACDCF8-5451-4E26-BDDB-E78D5830E93C}" diff --git a/resources/weapons/standoff/AGM-84A.yaml b/resources/weapons/standoff/AGM-84A.yaml deleted file mode 100644 index f0b8addbf..000000000 --- a/resources/weapons/standoff/AGM-84A.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-84A -year: 1979 -fallback: GBU-24 -clsids: - - "{8B7CADF9-4954-46B3-8CFB-93F2F5B90B03}" diff --git a/resources/weapons/standoff/AGM-84D.yaml b/resources/weapons/standoff/AGM-84D.yaml deleted file mode 100644 index da8f06548..000000000 --- a/resources/weapons/standoff/AGM-84D.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-84D -year: 1985 -fallback: AGM-84A -clsids: - - "{AGM_84D}" diff --git a/resources/weapons/standoff/AGM-84E.yaml b/resources/weapons/standoff/AGM-84E.yaml deleted file mode 100644 index a35316847..000000000 --- a/resources/weapons/standoff/AGM-84E.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: AGM-84E SLAM -year: 1990 -fallback: AGM-65G -clsids: - - "{AF42E6DF-9A60-46D8-A9A0-1708B241AADB}" - - "{AGM_84E}" diff --git a/resources/weapons/standoff/AGM-84H.yaml b/resources/weapons/standoff/AGM-84H.yaml deleted file mode 100644 index 38d1bf029..000000000 --- a/resources/weapons/standoff/AGM-84H.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-84H SLAM-ER -year: 2000 -fallback: AGM-84E SLAM -clsids: - - "{AGM_84H}" diff --git a/resources/weapons/standoff/AGM-86C-20X.yaml b/resources/weapons/standoff/AGM-86C-20X.yaml deleted file mode 100644 index 8dd0996a3..000000000 --- a/resources/weapons/standoff/AGM-86C-20X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 20xAGM-86C -year: 1988 -fallback: 8xAGM-86D -clsids: - - "{20_x_AGM_86C}" diff --git a/resources/weapons/standoff/AGM-86C-6X.yaml b/resources/weapons/standoff/AGM-86C-6X.yaml deleted file mode 100644 index 1752f2fa1..000000000 --- a/resources/weapons/standoff/AGM-86C-6X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 6xAGM-86C -year: 1988 -fallback: AGM-86D -clsids: - - "{6_x_AGM_86C_MER}" diff --git a/resources/weapons/standoff/AGM-86C-8X.yaml b/resources/weapons/standoff/AGM-86C-8X.yaml deleted file mode 100644 index 625a82f22..000000000 --- a/resources/weapons/standoff/AGM-86C-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 8xAGM-86C -year: 1988 -fallback: 6xAGM-86D -clsids: - - "{8_x_AGM_86C}" diff --git a/resources/weapons/standoff/AGM-86C.yaml b/resources/weapons/standoff/AGM-86C.yaml deleted file mode 100644 index fba4aaeef..000000000 --- a/resources/weapons/standoff/AGM-86C.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-86C -year: 1988 -fallback: 27xMk 82 -clsids: - - "{AGM_86C}" diff --git a/resources/weapons/standoff/AGM-86D-20X.yaml b/resources/weapons/standoff/AGM-86D-20X.yaml deleted file mode 100644 index 08c0dd041..000000000 --- a/resources/weapons/standoff/AGM-86D-20X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 20xAGM-86D -year: 2001 -fallback: 20xAGM-86C -clsids: - - "{22906569-A97F-404B-BA4F-D96DBF94D05E}" diff --git a/resources/weapons/standoff/AGM-86D-6X.yaml b/resources/weapons/standoff/AGM-86D-6X.yaml deleted file mode 100644 index 3a94ab60d..000000000 --- a/resources/weapons/standoff/AGM-86D-6X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 6xAGM-86D -year: 2001 -fallback: 6xAGM-86C -clsids: - - "{45447F82-01B5-4029-A572-9AAD28AF0275}" diff --git a/resources/weapons/standoff/AGM-86D-8X.yaml b/resources/weapons/standoff/AGM-86D-8X.yaml deleted file mode 100644 index 1aca3c13d..000000000 --- a/resources/weapons/standoff/AGM-86D-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: 8xAGM-86D -year: 2001 -fallback: 8xAGM-86C -clsids: - - "{8DCAF3A3-7FCF-41B8-BB88-58DEDA878EDE}" diff --git a/resources/weapons/standoff/AGM-86D.yaml b/resources/weapons/standoff/AGM-86D.yaml deleted file mode 100644 index db40adbda..000000000 --- a/resources/weapons/standoff/AGM-86D.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: AGM-86D -year: 2001 -fallback: AGM-86C -clsids: - - "{769A15DF-6AFB-439F-9B24-5B7A45C59D16}" diff --git a/resources/weapons/standoff/AGM-88C.yaml b/resources/weapons/standoff/AGM-88C.yaml deleted file mode 100644 index 35cc34dd2..000000000 --- a/resources/weapons/standoff/AGM-88C.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: AGM-88C HARM -# https://www.af.mil/About-Us/Fact-Sheets/Display/Article/104574/agm-88-harm/ -# 1984 is the date for the A variant but as we do not have that one we use it for C -year: 1984 -clsids: - - "{B06DD79A-F21E-4EB9-BD9D-AB3844618C9C}" - - "{B06DD79A-F21E-4EB9-BD9D-AB3844618C93}" diff --git a/resources/weapons/standoff/ALARM-2X.yaml b/resources/weapons/standoff/ALARM-2X.yaml deleted file mode 100644 index 9c6cfc5ce..000000000 --- a/resources/weapons/standoff/ALARM-2X.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: 2 x ALARM -type: ARM -clsids: - - "{07BE2D19-0E48-4B0B-91DA-5F6C8F9E3C75}" \ No newline at end of file diff --git a/resources/weapons/standoff/ALARM.yaml b/resources/weapons/standoff/ALARM.yaml deleted file mode 100644 index efeb5a5c2..000000000 --- a/resources/weapons/standoff/ALARM.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: ALARM -type: ARM -clsids: - - "{E6747967-B1F0-4C77-977B-AB2E6EB0C102}" \ No newline at end of file diff --git a/resources/weapons/standoff/BGM-71D-4X.yaml b/resources/weapons/standoff/BGM-71D-4X.yaml deleted file mode 100644 index 85349b4f4..000000000 --- a/resources/weapons/standoff/BGM-71D-4X.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: 4 x BGM-71D TOW ATGM -year: 1985 -# BGM-71A IOC in 1970 can be used as a stand-in until earlier variants are added to DCS. BGM-71D true IOC is 1985 -fallback: Brauning Gun Pod -clsids: - - "{3EA17AB0-A805-4D9E-8732-4CE00CB00F17}" diff --git a/resources/weapons/standoff/KH-25ML.yaml b/resources/weapons/standoff/KH-25ML.yaml deleted file mode 100644 index 958eca61f..000000000 --- a/resources/weapons/standoff/KH-25ML.yaml +++ /dev/null @@ -1,8 +0,0 @@ -name: KH-25ML -year: 1981 -# The base KH-25L IOCed in 1974, but does not appear to be in the game -fallback: S-25L -clsids: - - "{X-25ML}" - - "{6DADF342-D4BA-4D8A-B081-BA928C4AF86D}" - - "{79D73885-0801-45a9-917F-C90FE1CE3DFC}" diff --git a/resources/weapons/standoff/KH-25MP.yaml b/resources/weapons/standoff/KH-25MP.yaml deleted file mode 100644 index 98f1c0b1b..000000000 --- a/resources/weapons/standoff/KH-25MP.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KH-25MP -year: 1981 -fallback: KH-29L -clsids: - - "{Kh-25MP}" diff --git a/resources/weapons/standoff/KH-25MR.yaml b/resources/weapons/standoff/KH-25MR.yaml deleted file mode 100644 index d82a296ca..000000000 --- a/resources/weapons/standoff/KH-25MR.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: KH-25MR -year: 1974 -fallback: KH-66 Grohm -clsids: - - "{292960BB-6518-41AC-BADA-210D65D5073C}" - - "{X-25MR}" diff --git a/resources/weapons/standoff/KH-29L.yaml b/resources/weapons/standoff/KH-29L.yaml deleted file mode 100644 index f14d956eb..000000000 --- a/resources/weapons/standoff/KH-29L.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: KH-29L -year: 1980 -fallback: KH-25ML -clsids: - - "{X-29L}" - - "{3468C652-E830-4E73-AFA9-B5F260AB7C3D}" - - "{D4A8D9B9-5C45-42e7-BBD2-0E54F8308432}" diff --git a/resources/weapons/standoff/KH-29T.yaml b/resources/weapons/standoff/KH-29T.yaml deleted file mode 100644 index 9f7b99f32..000000000 --- a/resources/weapons/standoff/KH-29T.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: KH-29T -year: 1980 -fallback: KH-29L -clsids: - - "{B4FC81C9-B861-4E87-BBDC-A1158E648EBF}" - - "{601C99F7-9AF3-4ed7-A565-F8B8EC0D7AAC}" - - "{X-29T}" diff --git a/resources/weapons/standoff/KH-31A.yaml b/resources/weapons/standoff/KH-31A.yaml deleted file mode 100644 index 83232c36a..000000000 --- a/resources/weapons/standoff/KH-31A.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: KH-31A -year: 1989 -fallback: KH-29L -clsids: - - "{4D13E282-DF46-4B23-864A-A9423DFDE504}" - - "{4D13E282-DF46-4B23-864A-A9423DFDE50A}" - - "{X-31A}" diff --git a/resources/weapons/standoff/KH-35.yaml b/resources/weapons/standoff/KH-35.yaml deleted file mode 100644 index 483eed0b8..000000000 --- a/resources/weapons/standoff/KH-35.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: KH-35 -year: 2003 -fallback: KH-31A -clsids: - - "{2234F529-1D57-4496-8BB0-0150F9BDBBD2}" - - "{2234F529-1D57-4496-8BB0-0150F9BDBBD3}" diff --git a/resources/weapons/standoff/KH-59M.yaml b/resources/weapons/standoff/KH-59M.yaml deleted file mode 100644 index 0c882b7e6..000000000 --- a/resources/weapons/standoff/KH-59M.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: KH-59M -year: 1992 -# Base KH-59 (AS-13 Kingbolt) entered service in 1982 - had smaller warhead -fallback: KH-29T -clsids: - - "{40AB87E8-BEFB-4D85-90D9-B2753ACF9514}" diff --git a/resources/weapons/standoff/KH-65.yaml b/resources/weapons/standoff/KH-65.yaml deleted file mode 100644 index 2f66618d7..000000000 --- a/resources/weapons/standoff/KH-65.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KH-65 -year: 1992 -fallback: KH-59M -clsids: - - "{BADAF2DE-68B5-472A-8AAC-35BAEFF6B4A1}" diff --git a/resources/weapons/standoff/KH-66 Grohm.yaml b/resources/weapons/standoff/KH-66 Grohm.yaml deleted file mode 100644 index b0767498e..000000000 --- a/resources/weapons/standoff/KH-66 Grohm.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: KH-66 Grohm -year: 1968 -fallback: S-25OFM -clsids: - - "{Kh-66_Grom}" diff --git a/resources/weapons/standoff/Kh-25MPU.yaml b/resources/weapons/standoff/Kh-25MPU.yaml deleted file mode 100644 index 769c82865..000000000 --- a/resources/weapons/standoff/Kh-25MPU.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: KH-25MPU -year: 1985 -fallback: KH-25MP -clsids: - - "{E86C5AA5-6D49-4F00-AD2E-79A62D6DDE26}" - - "{752AF1D2-EBCC-4bd7-A1E7-2357F5601C70}" - - "{X-25MPU}" diff --git a/resources/weapons/standoff/Kh-31P.yaml b/resources/weapons/standoff/Kh-31P.yaml deleted file mode 100644 index 08ba75e42..000000000 --- a/resources/weapons/standoff/Kh-31P.yaml +++ /dev/null @@ -1,7 +0,0 @@ -name: KH-31P -year: 1988 -fallback: KH-25MPU -clsids: - - "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF03}" - - "{D8F2C90B-887B-4B9E-9FE2-996BC9E9AF0A}" - - "{X-31P}" diff --git a/resources/weapons/standoff/Kh-58U.yaml b/resources/weapons/standoff/Kh-58U.yaml deleted file mode 100644 index fb4165ba1..000000000 --- a/resources/weapons/standoff/Kh-58U.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: KH-58U -year: 1991 -fallback: KH-31P -clsids: - - "{FE382A68-8620-4AC0-BDF5-709BFE3977D7}" - - "{B5CA9846-776E-4230-B4FD-8BCC9BFB1676}" diff --git a/resources/weapons/standoff/LD-10-2X.yaml b/resources/weapons/standoff/LD-10-2X.yaml deleted file mode 100644 index 2877e7fd4..000000000 --- a/resources/weapons/standoff/LD-10-2X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: LD-10 x 2 -type: ARM -clsids: - - "DIS_LD-10_DUAL_L" - - "DIS_LD-10_DUAL_R" \ No newline at end of file diff --git a/resources/weapons/standoff/LD-10.yaml b/resources/weapons/standoff/LD-10.yaml deleted file mode 100644 index 0db774507..000000000 --- a/resources/weapons/standoff/LD-10.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: LD-10 -type: ARM -clsids: - - "DIS_LD-10" \ No newline at end of file diff --git a/resources/weapons/standoff/MAR-1.yaml b/resources/weapons/standoff/MAR-1.yaml deleted file mode 100644 index eb48437a3..000000000 --- a/resources/weapons/standoff/MAR-1.yaml +++ /dev/null @@ -1,4 +0,0 @@ -name: MAR-1 High Speed Anti-Radiation Missile -type: ARM -clsids: - - "{JAS39_MAR-1}" \ No newline at end of file diff --git a/resources/weapons/standoff/S-25L.yaml b/resources/weapons/standoff/S-25L.yaml deleted file mode 100644 index 62199609b..000000000 --- a/resources/weapons/standoff/S-25L.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: S-25L -year: 1979 -fallback: S-25O -clsids: - - "{0180F983-C14A-11d8-9897-000476191836}" diff --git a/resources/weapons/standoff/Vikhr-8X.yaml b/resources/weapons/standoff/Vikhr-8X.yaml deleted file mode 100644 index 367bc1976..000000000 --- a/resources/weapons/standoff/Vikhr-8X.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: Vikhr * 8 -year: 1985 -fallback: KH-29L -clsids: - - "{F789E86A-EE2E-4E6B-B81E-D5E5F903B6ED}" diff --git a/resources/weather/archetypes/clear.yaml b/resources/weather/archetypes/clear.yaml deleted file mode 100644 index d7d809bc3..000000000 --- a/resources/weather/archetypes/clear.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: clear -wind: - speed: - weibull: - at_msl: - shape: 1.5 - scale_kts: 5 - at_2000m: - shape: 3.5 - scale_kts: 20 - at_8000m: - shape: 6.4 - scale_kts: 20 diff --git a/resources/weather/archetypes/cloudy.yaml b/resources/weather/archetypes/cloudy.yaml deleted file mode 100644 index 9c7ea6c9f..000000000 --- a/resources/weather/archetypes/cloudy.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: cloudy -wind: - speed: - weibull: - at_msl: - shape: 1.6 - scale_kts: 6.5 - at_2000m: - shape: 3.5 - scale_kts: 22 - at_8000m: - shape: 6.4 - scale_kts: 18 diff --git a/resources/weather/archetypes/raining.yaml b/resources/weather/archetypes/raining.yaml deleted file mode 100644 index 7f6de023e..000000000 --- a/resources/weather/archetypes/raining.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: raining -wind: - speed: - weibull: - at_msl: - shape: 2.6 - scale_kts: 8 - at_2000m: - shape: 4.2 - scale_kts: 20 - at_8000m: - shape: 6.4 - scale_kts: 20 diff --git a/resources/weather/archetypes/thunderstorm.yaml b/resources/weather/archetypes/thunderstorm.yaml deleted file mode 100644 index fbccb672b..000000000 --- a/resources/weather/archetypes/thunderstorm.yaml +++ /dev/null @@ -1,14 +0,0 @@ ---- -id: thunderstorm -wind: - speed: - weibull: - at_msl: - shape: 6 - scale_kts: 20 - at_2000m: - shape: 6.2 - scale_kts: 20 - at_8000m: - shape: 6.4 - scale_kts: 20 diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/ato/__init__.py b/tests/ato/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/ato/flightstate/__init__.py b/tests/ato/flightstate/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/ato/flightstate/test_actionstate.py b/tests/ato/flightstate/test_actionstate.py deleted file mode 100644 index b62864e76..000000000 --- a/tests/ato/flightstate/test_actionstate.py +++ /dev/null @@ -1,29 +0,0 @@ -from collections.abc import Iterator -from datetime import timedelta, datetime - -from dcs.task import Task - -from game.ato.flightstate.actionstate import ActionState -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.flightplan.waypointactions.waypointaction import WaypointAction - - -class TestAction(WaypointAction): - def describe(self) -> str: - return "" - - def update_state( - self, state: ActionState, time: datetime, duration: timedelta - ) -> timedelta: - return timedelta() - - def iter_tasks(self, ctx: TaskContext) -> Iterator[Task]: - yield from [] - - -def test_actionstate() -> None: - action = TestAction() - state = ActionState(action) - assert not state.is_finished() - state.finish() - assert state.is_finished() diff --git a/tests/ato/test_flightplan.py b/tests/ato/test_flightplan.py deleted file mode 100644 index ed35683fc..000000000 --- a/tests/ato/test_flightplan.py +++ /dev/null @@ -1,85 +0,0 @@ -from typing import cast, Any - -import pytest -from dcs import Point -from dcs.terrain import Caucasus - -from game.ato import Flight, FlightWaypoint -from game.ato.flightplans.custom import CustomFlightPlan, CustomLayout -from game.ato.flightplans.flightplan import FlightPlan -from game.ato.flightwaypointtype import FlightWaypointType - - -@pytest.fixture(name="unescorted_flight_plan") -def unescorted_flight_plan_fixture() -> FlightPlan[Any]: - point = Point(0, 0, Caucasus()) - departure = FlightWaypoint("", FlightWaypointType.TAKEOFF, point) - - waypoints = [ - FlightWaypoint(f"{i}", FlightWaypointType.NAV, point) for i in range(10) - ] - return CustomFlightPlan(cast(Flight, object()), CustomLayout(departure, waypoints)) - - -@pytest.fixture(name="escorted_flight_plan") -def escorted_flight_plan_fixture() -> FlightPlan[Any]: - point = Point(0, 0, Caucasus()) - departure = FlightWaypoint("", FlightWaypointType.TAKEOFF, point) - - waypoints = [ - FlightWaypoint(f"{i}", FlightWaypointType.NAV, point) for i in range(10) - ] - waypoints[1].wants_escort = True - waypoints[2].wants_escort = True - waypoints[3].wants_escort = True - waypoints[5].wants_escort = True - waypoints[7].wants_escort = True - waypoints[8].wants_escort = True - return CustomFlightPlan(cast(Flight, object()), CustomLayout(departure, waypoints)) - - -def test_escorted_flight_plan_escorted_waypoints( - escorted_flight_plan: FlightPlan[Any], -) -> None: - assert [w.name for w in escorted_flight_plan.escorted_waypoints()] == [ - "1", - "2", - "3", - "5", - "7", - "8", - ] - - -def test_escorted_flight_plan_request_escort_at( - escorted_flight_plan: FlightPlan[Any], -) -> None: - wp = escorted_flight_plan.request_escort_at() - assert wp is not None - assert wp.name == "1" - - -def test_escorted_flight_plan_dismiss_escort_at( - escorted_flight_plan: FlightPlan[Any], -) -> None: - wp = escorted_flight_plan.dismiss_escort_at() - assert wp is not None - assert wp.name == "8" - - -def test_unescorted_flight_plan_escorted_waypoints( - unescorted_flight_plan: FlightPlan[Any], -) -> None: - assert not list(unescorted_flight_plan.escorted_waypoints()) - - -def test_unescorted_flight_plan_request_escort_at( - unescorted_flight_plan: FlightPlan[Any], -) -> None: - assert unescorted_flight_plan.request_escort_at() is None - - -def test_unescorted_flight_plan_dismiss_escort_at( - unescorted_flight_plan: FlightPlan[Any], -) -> None: - assert unescorted_flight_plan.dismiss_escort_at() is None diff --git a/tests/campaignloader/test_controlpointconfig.py b/tests/campaignloader/test_controlpointconfig.py deleted file mode 100644 index a252db6f8..000000000 --- a/tests/campaignloader/test_controlpointconfig.py +++ /dev/null @@ -1,30 +0,0 @@ -from game.campaignloader.controlpointconfig import ControlPointConfig - - -def test_from_empty_data() -> None: - config = ControlPointConfig.from_data({}) - assert not config.ferry_only - - -def test_from_data() -> None: - config = ControlPointConfig.from_data( - { - "ferry_only": True, - } - ) - assert config.ferry_only - - -def iter_from_data() -> None: - data = dict( - ControlPointConfig.iter_from_data( - { - 0: {}, - "named": {"ferry_only": True}, - } - ) - ) - assert data == { - 0: ControlPointConfig(ferry_only=False), - "named": ControlPointConfig(ferry_only=True), - } diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 3f6c1d1db..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,12 +0,0 @@ -from pathlib import Path -from zipfile import ZipFile - -import pytest - - -@pytest.fixture -def tmp_zip(tmp_path: Path) -> Path: - zip_path = tmp_path / "test.zip" - with ZipFile(zip_path, "w"): - pass - return zip_path diff --git a/tests/data/test_doctrine.py b/tests/data/test_doctrine.py deleted file mode 100644 index bd5c0c745..000000000 --- a/tests/data/test_doctrine.py +++ /dev/null @@ -1,43 +0,0 @@ -import pytest - -from game.data.doctrine import Doctrine, GroundUnitProcurementRatios -from game.data.units import UnitClass - - -def test_ground_unit_procurement_ratios_empty() -> None: - r = GroundUnitProcurementRatios({}) - for unit_class in UnitClass: - assert r.for_unit_class(unit_class) == 0.0 - - -def test_ground_unit_procurement_ratios_single_item() -> None: - r = GroundUnitProcurementRatios({UnitClass.TANK: 1}) - for unit_class in UnitClass: - if unit_class == UnitClass.TANK: - assert r.for_unit_class(unit_class) == 1.0 - else: - assert r.for_unit_class(unit_class) == 0.0 - - -def test_ground_unit_procurement_ratios_multiple_items() -> None: - r = GroundUnitProcurementRatios({UnitClass.TANK: 1, UnitClass.ATGM: 1}) - for unit_class in UnitClass: - if unit_class in [UnitClass.TANK, UnitClass.ATGM]: - assert r.for_unit_class(unit_class) == 0.5 - else: - assert r.for_unit_class(unit_class) == 0.0 - - -def test_ground_unit_procurement_ratios_from_dict() -> None: - r = GroundUnitProcurementRatios.from_dict({"Tank": 1, "ATGM": 1}) - for unit_class in UnitClass: - if unit_class in [UnitClass.TANK, UnitClass.ATGM]: - assert r.for_unit_class(unit_class) == 0.5 - else: - assert r.for_unit_class(unit_class) == 0.0 - - -def test_doctrine() -> None: - # This test checks for the presence of a doctrine named "modern" as this doctrine is used as a default - modern_doctrine = Doctrine.named("modern") - assert modern_doctrine.name == "modern" diff --git a/tests/dcs/__init__.py b/tests/dcs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/dcs/test_lasercodeconfig.py b/tests/dcs/test_lasercodeconfig.py deleted file mode 100644 index 61e7ff989..000000000 --- a/tests/dcs/test_lasercodeconfig.py +++ /dev/null @@ -1,64 +0,0 @@ -from game.dcs.lasercodeconfig import ( - SinglePropertyLaserCodeConfig, - MultiplePropertyLaserCodeConfig, - LaserCodeConfig, -) - - -def test_singlepropertylasercodeproperty() -> None: - config = SinglePropertyLaserCodeConfig("code", 3) - assert list(config.iter_prop_ids()) == ["code"] - assert config.property_dict_for_code(1688) == {"code": 688} - assert config.property_dict_for_code(1000) == {"code": 0} - assert config.property_dict_for_code(1234) == {"code": 234} - assert config.property_dict_for_code(1) == {"code": 1} - - -def test_multiplepropertylasercodeproperty() -> None: - config = MultiplePropertyLaserCodeConfig( - [ - ("digit0", 0), - ("digit1", 1), - ("digit2", 2), - ], - ) - assert list(config.iter_prop_ids()) == ["digit0", "digit1", "digit2"] - assert config.property_dict_for_code(1688) == { - "digit0": 8, - "digit1": 8, - "digit2": 6, - } - assert config.property_dict_for_code(1000) == { - "digit0": 0, - "digit1": 0, - "digit2": 0, - } - assert config.property_dict_for_code(1234) == { - "digit0": 4, - "digit1": 3, - "digit2": 2, - } - assert config.property_dict_for_code(1) == {"digit0": 1, "digit1": 0, "digit2": 0} - - -def test_lasercodeconfig_from_yaml() -> None: - config = LaserCodeConfig.from_yaml( - {"pylon": 0, "property": {"id": "code", "digits": 3}} - ) - assert config.property_dict_for_code(1688) == {"code": 688} - - config = LaserCodeConfig.from_yaml( - { - "pylon": 1, - "properties": [ - {"id": "digit0", "digit": 0}, - {"id": "digit1", "digit": 1}, - {"id": "digit2", "digit": 2}, - ], - } - ) - assert config.property_dict_for_code(1688) == { - "digit0": 8, - "digit1": 8, - "digit2": 6, - } diff --git a/tests/flightplan/__init__.py b/tests/flightplan/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/flightplan/test_ipsolver.py b/tests/flightplan/test_ipsolver.py deleted file mode 100644 index d1acc91a7..000000000 --- a/tests/flightplan/test_ipsolver.py +++ /dev/null @@ -1,101 +0,0 @@ -import random -import uuid -from collections.abc import Iterator -from contextlib import contextmanager -from pathlib import Path - -import pytest -from dcs.terrain import Caucasus -from shapely import Point, MultiPolygon, Polygon, unary_union - -from game.data.doctrine import Doctrine -from game.flightplan.ipsolver import IpSolver -from game.flightplan.waypointsolver import NoSolutionsError -from game.flightplan.waypointstrategy import point_at_heading -from game.utils import Heading, nautical_miles, feet, Distance, meters -from tests.flightplan.waypointsolvertestcasereducer import WaypointSolverTestCaseReducer - -# The Falklands is nearly 1000 nmi diagonal. We'll use that as a radius for a bit of -# overkill. -MAP_RADIUS = nautical_miles(1000) - -# Aircraft like the B-1 have a combat range closer to 3000 nmi, but we don't have -# maps big enough for that to matter. 600 nmi is still a *very* distant target for -# our campaigns. -MAX_TARGET_DISTANCE = nautical_miles(500) - -# 200 nmi is roughly the max range of the SA-5, which has the greatest range of -# anything in DCS. -MAX_THREAT_RANGE = nautical_miles(200) - -MAX_THREAT_DISTANCE = MAX_TARGET_DISTANCE + MAX_THREAT_RANGE - - -THIS_DIR = Path(__file__).parent -TEST_CASE_DIRECTORY = THIS_DIR / "testcases" - - -def fuzz_threat() -> Polygon: - threat_range_m = random.triangular( - feet(500).meters, MAX_THREAT_RANGE.meters, nautical_miles(40).meters - ) - threat_distance = meters( - random.triangular(0, MAX_THREAT_DISTANCE.meters, nautical_miles(100).meters) - ) - threat_position = point_at_heading(Point(0, 0), Heading.random(), threat_distance) - return threat_position.buffer(threat_range_m) - - -@pytest.fixture(name="fuzzed_target_distance") -def fuzzed_target_distance_fixture() -> Distance: - return meters( - random.triangular(0, MAX_TARGET_DISTANCE.meters, nautical_miles(100).meters) - ) - - -@pytest.fixture(name="fuzzed_threat_poly") -def fuzzed_threat_poly_fixture() -> MultiPolygon: - number_of_threats = random.randint(0, 100) - polys = unary_union([fuzz_threat() for _ in range(number_of_threats)]) - if isinstance(polys, MultiPolygon): - return polys - return MultiPolygon([polys]) - - -@pytest.fixture(name="fuzzed_solver") -def fuzzed_solver_fixture( - fuzzed_target_distance: Distance, fuzzed_threat_poly: MultiPolygon, tmp_path: Path -) -> IpSolver: - target_heading = Heading.from_degrees(random.uniform(0, 360)) - departure = Point(0, 0) - target = point_at_heading(departure, target_heading, fuzzed_target_distance) - solver = IpSolver( - departure, target, random.choice(Doctrine.all_doctrines()), fuzzed_threat_poly - ) - solver.set_debug_properties(tmp_path, Caucasus()) - return solver - - -@contextmanager -def capture_fuzz_failures(solver: IpSolver) -> Iterator[None]: - try: - yield - except NoSolutionsError as ex: - test_case_directory = TEST_CASE_DIRECTORY / str(uuid.uuid4()) - assert solver.debug_output_directory - WaypointSolverTestCaseReducer( - solver.debug_output_directory, test_case_directory - ).reduce() - ex.add_note(f"Reduced test case was written to {test_case_directory}") - raise - - -@pytest.mark.fuzztest -@pytest.mark.parametrize("run_number", range(500)) -def test_fuzz_ipsolver(fuzzed_solver: IpSolver, run_number: int) -> None: - with capture_fuzz_failures(fuzzed_solver): - fuzzed_solver.solve() - - -def test_can_construct_solver_with_empty_threat() -> None: - IpSolver(Point(0, 0), Point(0, 0), Doctrine.named("coldwar"), MultiPolygon([])) diff --git a/tests/flightplan/test_waypointsolver.py b/tests/flightplan/test_waypointsolver.py deleted file mode 100644 index 2650d99c7..000000000 --- a/tests/flightplan/test_waypointsolver.py +++ /dev/null @@ -1,231 +0,0 @@ -import json -from collections.abc import Iterator -from pathlib import Path - -import pytest -from dcs.terrain import Caucasus -from shapely.geometry import Point, MultiPolygon -from shapely.geometry.base import BaseGeometry - -from game.flightplan.waypointsolver import WaypointSolver, NoSolutionsError -from game.flightplan.waypointstrategy import WaypointStrategy - - -class NoSolutionsStrategy(WaypointStrategy): - def __init__(self) -> None: - super().__init__(MultiPolygon([])) - - def find(self) -> Point | None: - return None - - -class PointStrategy(WaypointStrategy): - def __init__(self, x: float, y: float) -> None: - super().__init__(MultiPolygon([])) - self.point = Point(x, y) - - def find(self) -> Point | None: - return self.point - - -class OriginStrategy(PointStrategy): - def __init__(self) -> None: - super().__init__(0, 0) - - -class DebuggableStrategy(NoSolutionsStrategy): - def __init__(self, distance_factor: int) -> None: - super().__init__() - center = Point(0, 0) - self.exclude("foo", center.buffer(1 * distance_factor)) - self.exclude( - "bar", - center.buffer(3 * distance_factor).difference( - center.buffer(2 * distance_factor) - ), - ) - - -class SolverWithInputs(WaypointSolver): - def describe_inputs(self) -> Iterator[tuple[str, BaseGeometry]]: - yield "foo", Point(0, 0) - yield "bar", Point(1, 1) - - -def test_solver_tries_strategies_in_order() -> None: - solver = WaypointSolver() - solver.add_strategy(OriginStrategy()) - solver.add_strategy(PointStrategy(1, 1)) - assert solver.solve() == Point(0, 0) - - -def test_individual_failed_strategies_do_not_fail_solver() -> None: - solver = WaypointSolver() - solver.add_strategy(NoSolutionsStrategy()) - solver.add_strategy(OriginStrategy()) - assert solver.solve() == Point(0, 0) - - -def test_no_solutions_raises() -> None: - solver = WaypointSolver() - solver.add_strategy(NoSolutionsStrategy()) - with pytest.raises(NoSolutionsError): - solver.solve() - - -def test_no_strategies_raises() -> None: - solver = WaypointSolver() - with pytest.raises(ValueError): - solver.solve() - - -def test_success_does_not_dump_debug_info(tmp_path: Path) -> None: - solver = WaypointSolver() - solver.set_debug_properties(tmp_path, Caucasus()) - solver.add_strategy(OriginStrategy()) - solver.solve() - assert not list(tmp_path.iterdir()) - - -def test_no_solutions_dumps_debug_info(tmp_path: Path) -> None: - center = Point(0, 0) - solver = WaypointSolver() - solver.set_debug_properties(tmp_path, Caucasus()) - strategy_0 = DebuggableStrategy(distance_factor=1) - strategy_1 = DebuggableStrategy(distance_factor=2) - strategy_1.prerequisite(center).is_safe() - solver.add_strategy(strategy_0) - solver.add_strategy(strategy_1) - with pytest.raises(NoSolutionsError): - solver.solve() - - strategy_0_path = tmp_path / "0.json" - strategy_1_path = tmp_path / "1.json" - assert set(tmp_path.iterdir()) == { - tmp_path / "solver.json", - strategy_0_path, - strategy_1_path, - } - - with strategy_0_path.open("r", encoding="utf-8") as metadata_file: - data = json.load(metadata_file) - assert data["type"] == "FeatureCollection" - assert data["metadata"]["name"] == "DebuggableStrategy" - assert data["metadata"]["prerequisites"] == [] - assert len(data.keys()) == 3 - features = data["features"] - assert len(features) == 2 - for debug_info, feature in zip(strategy_0.iter_debug_info(), features): - assert debug_info.to_geojson(solver.to_geojson) == feature - - with strategy_1_path.open("r", encoding="utf-8") as metadata_file: - data = json.load(metadata_file) - assert data["type"] == "FeatureCollection" - assert data["metadata"]["name"] == "DebuggableStrategy" - assert data["metadata"]["prerequisites"] == [ - { - "requirement": "is safe", - "satisfied": True, - "subject": solver.to_geojson(center), - } - ] - assert len(data.keys()) == 3 - features = data["features"] - assert len(features) == 2 - for debug_info, feature in zip(strategy_1.iter_debug_info(), features): - assert debug_info.to_geojson(solver.to_geojson) == feature - - -def test_no_solutions_dumps_inputs(tmp_path: Path) -> None: - solver = SolverWithInputs() - solver.set_debug_properties(tmp_path, Caucasus()) - solver.add_strategy(NoSolutionsStrategy()) - with pytest.raises(NoSolutionsError): - solver.solve() - - inputs_path = tmp_path / "solver.json" - with inputs_path.open(encoding="utf-8") as inputs_file: - data = json.load(inputs_file) - assert data == { - "type": "FeatureCollection", - "metadata": { - "name": "SolverWithInputs", - "terrain": "Caucasus", - }, - "features": [ - { - "type": "Feature", - "properties": {"description": "foo"}, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.129497060328966], - }, - }, - { - "type": "Feature", - "properties": {"description": "bar"}, - "geometry": { - "type": "Point", - "coordinates": [34.265528100962584, 45.1295059189547], - }, - }, - ], - } - - -def test_solver_inputs_appear_in_strategy_features(tmp_path: Path) -> None: - solver = SolverWithInputs() - solver.set_debug_properties(tmp_path, Caucasus()) - solver.add_strategy(PointStrategy(2, 2)) - solver.dump_debug_info() - - strategy_path = tmp_path / "0.json" - with strategy_path.open(encoding="utf-8") as inputs_file: - data = json.load(inputs_file) - assert data == { - "type": "FeatureCollection", - "metadata": { - "name": "PointStrategy", - "prerequisites": [], - }, - "features": [ - { - "type": "Feature", - "properties": {"description": "foo"}, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.129497060328966], - }, - }, - { - "type": "Feature", - "properties": {"description": "bar"}, - "geometry": { - "type": "Point", - "coordinates": [34.265528100962584, 45.1295059189547], - }, - }, - { - "type": "Feature", - "properties": {"description": "solution"}, - "geometry": { - "coordinates": [34.265541013473154, 45.12951477757893], - "type": "Point", - }, - }, - ], - } - - -def test_to_geojson(tmp_path: Path) -> None: - solver = WaypointSolver() - solver.set_debug_properties(tmp_path, Caucasus()) - assert solver.to_geojson(Point(0, 0)) == { - "coordinates": [34.265515188456, 45.129497060328966], - "type": "Point", - } - - assert solver.to_geojson(MultiPolygon([])) == { - "type": "MultiPolygon", - "coordinates": [], - } diff --git a/tests/flightplan/test_waypointsolver_regression_tests.py b/tests/flightplan/test_waypointsolver_regression_tests.py deleted file mode 100644 index 40de20b2b..000000000 --- a/tests/flightplan/test_waypointsolver_regression_tests.py +++ /dev/null @@ -1,23 +0,0 @@ -from pathlib import Path - -import pytest - -from game.flightplan.waypointsolverloader import WaypointSolverLoader - -THIS_DIR = Path(__file__).parent -TEST_CASES_DIR = THIS_DIR / "testcases" - -# Set to True to regenerate the debug files for each test case. After doing this, format -# the test cases with `npx prettier -w tests/flightplan/testcases` for readability. -UPDATE_TEST_CASES = False - - -@pytest.mark.parametrize("test_case", TEST_CASES_DIR.glob("**/solver.json")) -def test_waypoint_solver_regression_tests(test_case: Path) -> None: - loader = WaypointSolverLoader(test_case) - solver = loader.load() - if UPDATE_TEST_CASES: - solver.set_debug_properties(test_case.parent, loader.terrain) - solver.solve() - if UPDATE_TEST_CASES: - solver.dump_debug_info() diff --git a/tests/flightplan/test_waypointsolverloader.py b/tests/flightplan/test_waypointsolverloader.py deleted file mode 100644 index c8fe8386f..000000000 --- a/tests/flightplan/test_waypointsolverloader.py +++ /dev/null @@ -1,54 +0,0 @@ -import json -from pathlib import Path - -import pytest - -from game.flightplan.ipsolver import IpSolver -from game.flightplan.waypointsolverloader import WaypointSolverLoader - - -def test_waypointsolverloader(tmp_path: Path) -> None: - debug_info_path = tmp_path / "solver.json" - debug_info_path.write_text( - json.dumps( - { - "type": "FeatureCollection", - "metadata": { - "name": "IpSolver", - "terrain": "Falklands", - "doctrine": "coldwar", - }, - "features": [ - { - "type": "Feature", - "properties": {"description": "departure"}, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296], - }, - }, - { - "type": "Feature", - "properties": {"description": "target"}, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211], - }, - }, - { - "type": "Feature", - "properties": {"description": "threat_zones"}, - "geometry": {"type": "MultiPolygon", "coordinates": []}, - }, - ], - } - ) - ) - solver = WaypointSolverLoader(debug_info_path).load() - assert isinstance(solver, IpSolver) - assert solver.doctrine.name == "coldwar" - assert solver.threat_zones.is_empty - assert solver.departure.x == pytest.approx(0, abs=1e-8) - assert solver.departure.y == pytest.approx(0, abs=1e-8) - assert solver.target.x == pytest.approx(-5436.058, abs=0.001) - assert solver.target.y == pytest.approx(3138.51, abs=0.001) diff --git a/tests/flightplan/test_waypointstrategy.py b/tests/flightplan/test_waypointstrategy.py deleted file mode 100644 index eeb447d99..000000000 --- a/tests/flightplan/test_waypointstrategy.py +++ /dev/null @@ -1,190 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import pytest -from pytest import approx -from shapely.geometry import Point, MultiPolygon - -from game.flightplan.waypointstrategy import WaypointStrategy, angle_between_points -from game.utils import meters, Heading - - -def test_safe_prerequisite_safe_point() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - strategy.prerequisite(Point(0, 0)).is_safe() - assert strategy.prerequisites_are_satisfied() - - -def test_safe_prerequisite_unsafe_point() -> None: - strategy = WaypointStrategy(MultiPolygon([Point(0, 0).buffer(1)])) - strategy.prerequisite(Point(0, 0)).is_safe() - assert not strategy.prerequisites_are_satisfied() - - -def test_no_solution_if_prerequisites_failed() -> None: - """Verify that no solution is found if prerequisites are not satisfied. - - This test has a 1-meter radius threat zone about the center of the plane. It has a - prerequisite for a safe center, which will fail. The test verifies that even if - there are no .require() constraints that would prevent finding a solution, failed - prerequisites still prevent it (prerequisites differ from constraints in that they - will prevent any of the other operations from happening without needing to location - constraints, which is important because it allows strategies to avoid defending - against invalid cases). - """ - strategy = WaypointStrategy(MultiPolygon([Point(0, 0).buffer(1)])) - strategy.prerequisite(Point(0, 0)).is_safe() - # This constraint won't actually apply, but it's required before calling find() so - # we need to set it even though it's not actually relevant to the test. - strategy.nearest(Point(0, 0)) - assert strategy.find() is None - - -def test_has_solution_if_prerequisites_satisfied() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - strategy.prerequisite(Point(0, 0)).is_safe() - strategy.nearest(Point(0, 0)) - assert strategy.find() is not None - - -def test_require_nearest() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - center = Point(0, 0) - strategy.nearest(center) - assert strategy.find() == center - - -def test_find_without_nearest_raises() -> None: - with pytest.raises(RuntimeError): - WaypointStrategy(MultiPolygon([])).find() - - -def test_multiple_nearest_raises() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - strategy.nearest(Point(0, 0)) - with pytest.raises(RuntimeError): - strategy.nearest(Point(0, 0)) - - -def test_require_at_least() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - center = Point(0, 0) - strategy.require().at_least(meters(10)).away_from(center) - strategy.nearest(center) - solution = strategy.find() - assert solution is not None - assert solution.distance(center) == approx(10, 0.1) - - -def test_require_at_most() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - center = Point(0, 0) - strategy.require().at_most(meters(1)).away_from(center) - strategy.nearest(Point(10, 0)) - solution = strategy.find() - assert solution is not None - assert solution.distance(center) <= 1 - - -def test_require_safe() -> None: - threat = MultiPolygon([Point(0, 0).buffer(10)]) - strategy = WaypointStrategy(threat) - strategy.require().safe() - strategy.nearest(Point(0, 0)) - solution = strategy.find() - assert solution is not None - assert not solution.intersects(threat) - - -def test_require_maximum_turn_to() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - turn_point = Point(1, 0) - turn_target = Point(0, 0) - strategy.require().maximum_turn_to(turn_point, turn_target, Heading(90)) - strategy.nearest(Point(0, 1)) - pre_turn_heading = Heading.from_degrees( - angle_between_points(strategy.find(), turn_point) - ) - post_turn_heading = Heading.from_degrees( - angle_between_points(turn_point, turn_target) - ) - assert pre_turn_heading.angle_between(post_turn_heading) <= Heading(90) - - -def test_combined_constraints() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - center = Point(0, 0) - offset = Point(1, 0) - midpoint = Point(0.5, 0) - strategy.require().at_least(meters(1)).away_from(center) - strategy.require().at_least(meters(1)).away_from(offset) - strategy.nearest(midpoint) - solution = strategy.find() - assert solution is not None - assert solution.distance(center) == approx(1, rel=0.1, abs=0.1) - assert solution.distance(offset) == approx(1, rel=0.1, abs=0.1) - assert solution.distance(midpoint) < 1 - - -def test_threat_tolerance(tmp_path: Path) -> None: - home = Point(20, 0) - target = Point(-1, 0) - max_distance = meters(5) - threat = MultiPolygon([Point(0, 0).buffer(10)]) - strategy = WaypointStrategy(threat) - strategy.require().at_most(max_distance).away_from(target) - strategy.threat_tolerance(target, max_distance, meters(1)) - strategy.require().safe() - strategy.nearest(home) - solution = strategy.find() - assert solution is not None - # Max distance of 5 from -1, so the point should be at 4. Home is at 20. - assert solution.distance(home) == 16 - - -def test_threat_tolerance_does_nothing_if_no_threats(tmp_path: Path) -> None: - strategy = WaypointStrategy(MultiPolygon([])) - strategy.threat_tolerance(Point(0, 0), meters(1), meters(1)) - assert strategy._threat_tolerance is None - - -def test_no_solutions() -> None: - strategy = WaypointStrategy(MultiPolygon([])) - strategy.require().at_most(meters(1)).away_from(Point(0, 0)) - strategy.require().at_least(meters(2)).away_from(Point(0, 0)) - strategy.nearest(Point(0, 0)) - assert strategy.find() is None - - -def test_debug() -> None: - center = Point(0, 0) - threat = MultiPolygon([center.buffer(5)]) - strategy = WaypointStrategy(threat) - strategy.require().at_most(meters(10)).away_from(center, "center") - strategy.require().at_least(meters(2)).away_from(center) - strategy.require().safe() - strategy.nearest(center) - solution = strategy.find() - assert solution is not None - debug_info = list(strategy.iter_debug_info()) - assert len(debug_info) == 4 - max_distance_debug, min_distance_debug, safe_debug, solution_debug = debug_info - assert max_distance_debug.description == "at most 10 meters away from center" - assert max_distance_debug.geometry.distance(center) == approx(10, 0.1) - assert min_distance_debug.description == "at least 2 meters away from POINT (0 0)" - assert max_distance_debug.geometry.boundary.distance(center) == approx(10, 0.1) - assert safe_debug.description == "safe" - assert safe_debug.geometry == threat - assert solution_debug.description == "solution" - assert solution_debug.geometry == solution - - -def test_debug_info_omits_solution_if_none() -> None: - center = Point(0, 0) - strategy = WaypointStrategy(MultiPolygon([])) - strategy.require().at_most(meters(1)).away_from(center) - strategy.require().at_least(meters(2)).away_from(center) - strategy.nearest(center) - debug_infos = list(strategy.iter_debug_info()) - assert len(debug_infos) == 2 diff --git a/tests/flightplan/testcases/ip-backtracking-required/0.json b/tests/flightplan/testcases/ip-backtracking-required/0.json deleted file mode 100644 index da29dda75..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/0.json +++ /dev/null @@ -1,362 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "SafeIpStrategy", - "prerequisites": [ - { - "requirement": "is safe", - "satisfied": true, - "subject": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "requirement": "at least 18520 meters between", - "satisfied": false, - "subject": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - }, - "target": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.1694286601329, -52.38573739719403], - [-59.182774836264244, -52.38589254392049], - [-59.19603230328524, -52.38684587084007], - [-59.209074089262515, -52.3885882399017], - [-59.22177525596318, -52.391102955103605], - [-59.23401407684473, -52.39436592009533], - [-59.24567318670733, -52.398345865610736], - [-59.2566406927957, -52.40300464471517], - [-59.26681123738075, -52.408297593245116], - [-59.276087002163194, -52.41417395222987], - [-59.28437864522447, -52.42057734851895], - [-59.29160616170672, -52.42744632929708], - [-59.297699659936825, -52.43471494565813], - [-59.30260004532041, -52.44231337993217], - [-59.30625960502348, -52.45016861102354], - [-59.30864248723164, -52.458205111623066], - [-59.309725069629614, -52.46634557081417], - [-59.30949621267497, -52.47451163530008], - [-59.307957394246614, -52.4826246622458], - [-59.30512272332469, -52.490606476557], - [-59.30101883149693, -52.49838012531171], - [-59.29568464227776, -52.50587062202425], - [-59.28917101945945, -52.51300567345666], - [-59.2815402969746, -52.519716381802446], - [-59.27286569402213, -52.52593791525311], - [-59.26323062047682, -52.53161014021919], - [-59.2527278788472, -52.53667820881417], - [-59.241458770249146, -52.541093095619], - [-59.22953211300261, -52.54481207822556], - [-59.21706318351819, -52.5477991566033], - [-59.20417259009765, -52.55002540694027], - [-59.19098509111309, -52.551469266271], - [-59.177628369734414, -52.55211674491189], - [-59.1642317779319, -52.55196156447031], - [-59.15092506287909, -52.551005219969966], - [-59.13783708911096, -52.54925696542863], - [-59.12509456985153, -52.546733723028545], - [-59.112820820809006, -52.543459916821654], - [-59.10113454945126, -52.539467232702386], - [-59.09014869232144, -52.534794307148545], - [-59.07996931234633, -52.529486347968145], - [-59.07069456733568, -52.52359469098489], - [-59.06241375998853, -52.51717629724248], - [-59.05520647872498, -52.51029319589711], - [-59.04914183756979, -52.50301187849567], - [-59.04427782214608, -52.495402650795825], - [-59.04066074761231, -52.487538948672174], - [-59.03832483311475, -52.47949662496506], - [-59.03729189604848, -52.471353214365486], - [-59.037571168142264, -52.46318718358906], - [-59.03915923412195, -52.45507717417564], - [-59.042040092478956, -52.44710124526024], - [-59.04618533668858, -52.439336123597194], - [-59.05155445409762, -52.43185646798682], - [-59.058095238641386, -52.42473415505608], - [-59.06574431256431, -52.41803759308379], - [-59.074427751409445, -52.41183107024558], - [-59.08406180571499, -52.406174143283636], - [-59.094553712110944, -52.40112107219045], - [-59.10580258584608, -52.39672030603672], - [-59.11770038619459, -52.393014024577106], - [-59.13013294569025, -52.39003773973814], - [-59.1429810537112, -52.38781996053568], - [-59.15612158458851, -52.38638192438844], - [-59.1694286601329, -52.38573739719403] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-61.24520650893593, -43.58579503441036], - [-62.43900162590413, -43.7497691803044], - [-63.612493495637935, -43.98526799486243], - [-64.75854728127679, -44.29048284578168], - [-65.8700825921841, -44.66312804387328], - [-66.94006272166334, -45.1004732252497], - [-67.9614737741224, -45.59937659973779], - [-68.92729370338857, -46.15631640527768], - [-69.83045219128213, -46.76741801639982], - [-70.66378326655452, -47.42847443676813], - [-71.41997361090772, -48.13495833299394], - [-72.09151065439988, -48.882024310623756], - [-72.6706358782252, -49.664500770531255], - [-73.14931027864807, -50.476871403171394], - [-73.51920075465131, -51.31324718174949], - [-73.77169828311617, -52.167330620433404], - [-73.89798108443222, -53.03237509921963], - [-73.88913836949948, -53.90114325644239], - [-73.73637229116584, -54.76586983775868], - [-73.43129667883855, -55.61823596017793], - [-72.96634988358412, -56.44936343019421], - [-72.33533402340117, -57.24983936549483], - [-71.53408218355598, -58.00978256805621], - [-70.56123686602989, -58.718963338760304], - [-69.41909630797443, -59.36698696897535], - [-68.11445159665061, -59.94354715854076], - [-66.6593020132534, -60.43874842291802], - [-65.07130869580571, -60.84348608774121], - [-63.373841197634476, -61.14985974334563], - [-61.59550107201298, -61.35158347731795], - [-59.769076979770325, -61.44434744422618], - [-57.92998819038475, -61.4260841620998], - [-56.11438242397838, -61.297101661684735], - [-54.357135124600056, -61.06006358545125], - [-52.69002133019903, -60.71981951054116], - [-51.14028922561234, -60.28311106090644], - [-49.729771998013284, -59.758195045596224], - [-48.474564115067665, -59.15443076016106], - [-47.38519289556456, -58.48187497961913], - [-46.46715720227685, -57.750917958459475], - [-45.72168645238335, -56.97198083003314], - [-45.14658626457788, -56.15528252407841], - [-44.73706796700835, -55.310674728097155], - [-44.48649497754395, -54.44753717268912], - [-44.387011124193485, -53.57472233140239], - [-44.430040299351845, -52.70053774185403], - [-44.60666284083145, -51.832754751180374], - [-44.90788297302482, -50.97863387520219], - [-45.324805438658956, -50.144958652578566], - [-45.84873994638991, -49.33807158107319], - [-46.47125070424038, -48.5639072973302], - [-47.18416610732345, -47.82801955351357], - [-47.97956121781107, -47.13559975539399], - [-48.84972334727718, -46.491485880558855], - [-49.78710896857661, -45.90016151854075], - [-50.78429837575387, -45.36574558456223], - [-51.833952947595336, -44.89197395974785], - [-52.92877850338137, -44.48217489381598], - [-54.061497019491156, -44.13924045137882], - [-55.2248278682477, -43.86559656447767], - [-56.411478731061244, -43.66317434755541], - [-57.61414543189189, -43.5333852208467], - [-58.825519155892074, -43.477102072976976], - [-60.038298892920785, -43.49464819107359], - [-61.24520650893593, -43.58579503441036] - ], - [ - [-59.1429810537112, -52.38781996053568], - [-59.13013294569025, -52.39003773973814], - [-59.11770038619459, -52.393014024577106], - [-59.10580258584608, -52.39672030603672], - [-59.094553712110944, -52.40112107219045], - [-59.08406180571499, -52.406174143283636], - [-59.074427751409445, -52.41183107024558], - [-59.06574431256431, -52.41803759308379], - [-59.058095238641386, -52.42473415505608], - [-59.05155445409762, -52.43185646798682], - [-59.04618533668858, -52.439336123597194], - [-59.042040092478956, -52.44710124526024], - [-59.03915923412195, -52.45507717417564], - [-59.037571168142264, -52.46318718358906], - [-59.03729189604848, -52.471353214365486], - [-59.03832483311475, -52.47949662496506], - [-59.04066074761231, -52.487538948672174], - [-59.04427782214608, -52.495402650795825], - [-59.04914183756979, -52.50301187849567], - [-59.05520647872498, -52.51029319589711], - [-59.06241375998853, -52.51717629724248], - [-59.07069456733568, -52.52359469098489], - [-59.07996931234633, -52.529486347968145], - [-59.09014869232144, -52.534794307148545], - [-59.10113454945126, -52.539467232702386], - [-59.112820820809006, -52.543459916821654], - [-59.12509456985153, -52.546733723028545], - [-59.13783708911096, -52.54925696542863], - [-59.15092506287909, -52.551005219969966], - [-59.1642317779319, -52.55196156447031], - [-59.177628369734414, -52.55211674491189], - [-59.19098509111309, -52.551469266271], - [-59.20417259009765, -52.55002540694027], - [-59.21706318351819, -52.5477991566033], - [-59.22953211300261, -52.54481207822556], - [-59.241458770249146, -52.541093095619], - [-59.2527278788472, -52.53667820881417], - [-59.26323062047682, -52.53161014021919], - [-59.27286569402213, -52.52593791525311], - [-59.2815402969746, -52.519716381802446], - [-59.28917101945945, -52.51300567345666], - [-59.29568464227776, -52.50587062202425], - [-59.30101883149693, -52.49838012531171], - [-59.30512272332469, -52.490606476557], - [-59.307957394246614, -52.4826246622458], - [-59.30949621267497, -52.47451163530008], - [-59.309725069629614, -52.46634557081417], - [-59.30864248723164, -52.458205111623066], - [-59.30625960502348, -52.45016861102354], - [-59.30260004532041, -52.44231337993217], - [-59.297699659936825, -52.43471494565813], - [-59.29160616170672, -52.42744632929708], - [-59.28437864522447, -52.42057734851895], - [-59.276087002163194, -52.41417395222987], - [-59.26681123738075, -52.408297593245116], - [-59.2566406927957, -52.40300464471517], - [-59.24567318670733, -52.398345865610736], - [-59.23401407684473, -52.39436592009533], - [-59.22177525596318, -52.391102955103605], - [-59.209074089262515, -52.3885882399017], - [-59.19603230328524, -52.38684587084007], - [-59.182774836264244, -52.38589254392049], - [-59.1694286601329, -52.38573739719403], - [-59.15612158458851, -52.38638192438844], - [-59.1429810537112, -52.38781996053568] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 18520 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.121698601708005, -52.35221938878728], - [-59.1483707669824, -52.352539181791855], - [-59.174864956379174, -52.354452308599825], - [-59.200928824878766, -52.35794051703288], - [-59.22631399917205, -52.36297054867728], - [-59.25077836975904, -52.36949444660461], - [-59.274088332830544, -52.37744999898237], - [-59.29602096370069, -52.38676131496918], - [-59.31636610373802, -52.39733952820188], - [-59.334928342990615, -52.40908362210935], - [-59.35152888103252, -52.4218813702365], - [-59.36600724899414, -52.43561038373551], - [-59.37822287629847, -52.450139257187445], - [-59.38805648633034, -52.46532880296285], - [-59.395411306136786, -52.48103336342364], - [-59.40021407631661, -52.49710218942012], - [-59.40241584851922, -52.51338087275744], - [-59.40199255945591, -52.52971281960737], - [-59.39894537203628, -52.54594075123524], - [-59.39330077618356, -52.561908217914066], - [-59.38511044405171, -52.57746111151858], - [-59.374450836751734, -52.59244916204673], - [-59.3614225622759, -52.60672740321651], - [-59.34614948705774, -52.620157592342395], - [-59.3287776064854, -52.63260956991959], - [-59.30947368265184, -52.643962544740546], - [-59.28842366062458, -52.65410629094276], - [-59.26583087749274, -52.662942244140226], - [-59.2419140813369, -52.67038448472035], - [-59.21690528000393, -52.67636059748767], - [-59.19104744209, -52.68081239809494], - [-59.16459207477728, -52.683696518105506], - [-59.13779670507807, -52.68498484206297], - [-59.11092229256151, -52.68466479157966], - [-59.084230602734344, -52.68273945317297], - [-59.05798157088611, -52.67922754835072], - [-59.03243068637424, -52.67416324624244], - [-59.0078264270101, -52.66759582086878], - [-58.98440777242225, -52.65958915690083], - [-58.96240182403855, -52.65022110946301], - [-58.94202155767735, -52.63958272514549], - [-58.92346373271497, -52.627777332894894], - [-58.90690697945177, -52.61491951482181], - [-58.89251008369364, -52.601133968183774], - [-58.880410484761896, -52.586554270859715], - [-58.87072300020584, -52.57132156351448], - [-58.86353878748618, -52.555583162357834], - [-58.858924549881515, -52.53949111692515], - [-58.856921990905285, -52.52320072765201], - [-58.857547518654094, -52.50686903818477], - [-58.86079219878598, -52.49065331737245], - [-58.86662195228274, -52.47470954573185], - [-58.874977991810596, -52.45919092087807], - [-58.88577748837689, -52.44424639598174], - [-58.89891445809545, -52.43001926476255], - [-58.91426085722352, -52.41664580587255], - [-58.93166787221224, -52.40425399877453], - [-58.95096739031223, -52.392962322392755], - [-58.97197363527894, -52.38287864691966], - [-58.99448495191189, -52.37409922821219], - [-59.01828572251772, -52.36670781321734], - [-59.04314839788572, -52.36077486383433], - [-59.06883562498646, -52.35635690556254], - [-59.09510245332768, -52.353496006203315], - [-59.121698601708005, -52.35221938878728] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from target" - }, - "geometry": { "type": "Polygon", "coordinates": [[]] } - }, - { - "type": "Feature", - "properties": { "description": "safe" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - } - ] -} diff --git a/tests/flightplan/testcases/ip-backtracking-required/1.json b/tests/flightplan/testcases/ip-backtracking-required/1.json deleted file mode 100644 index 7293ca9a7..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/1.json +++ /dev/null @@ -1,351 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "ThreatTolerantIpStrategy", - "prerequisites": [ - { - "requirement": "at least 18520 meters between", - "satisfied": false, - "subject": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - }, - "target": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from POINT (0.0000000018626451 -0.0000000000582077)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.1694286601329, -52.38573739719403], - [-59.182774836264244, -52.38589254392049], - [-59.19603230328524, -52.38684587084007], - [-59.209074089262515, -52.3885882399017], - [-59.22177525596318, -52.391102955103605], - [-59.23401407684473, -52.39436592009533], - [-59.24567318670733, -52.398345865610736], - [-59.2566406927957, -52.40300464471517], - [-59.26681123738075, -52.408297593245116], - [-59.276087002163194, -52.41417395222987], - [-59.28437864522447, -52.42057734851895], - [-59.29160616170672, -52.42744632929708], - [-59.297699659936825, -52.43471494565813], - [-59.30260004532041, -52.44231337993217], - [-59.30625960502348, -52.45016861102354], - [-59.30864248723164, -52.458205111623066], - [-59.309725069629614, -52.46634557081417], - [-59.30949621267497, -52.47451163530008], - [-59.307957394246614, -52.4826246622458], - [-59.30512272332469, -52.490606476557], - [-59.30101883149693, -52.49838012531171], - [-59.29568464227776, -52.50587062202425], - [-59.28917101945945, -52.51300567345666], - [-59.2815402969746, -52.519716381802446], - [-59.27286569402213, -52.52593791525311], - [-59.26323062047682, -52.53161014021919], - [-59.2527278788472, -52.53667820881417], - [-59.241458770249146, -52.541093095619], - [-59.22953211300261, -52.54481207822556], - [-59.21706318351819, -52.5477991566033], - [-59.20417259009765, -52.55002540694027], - [-59.19098509111309, -52.551469266271], - [-59.177628369734414, -52.55211674491189], - [-59.1642317779319, -52.55196156447031], - [-59.15092506287909, -52.551005219969966], - [-59.13783708911096, -52.54925696542863], - [-59.12509456985153, -52.546733723028545], - [-59.112820820809006, -52.543459916821654], - [-59.10113454945126, -52.539467232702386], - [-59.09014869232144, -52.534794307148545], - [-59.07996931234633, -52.529486347968145], - [-59.07069456733568, -52.52359469098489], - [-59.06241375998853, -52.51717629724248], - [-59.05520647872498, -52.51029319589711], - [-59.04914183756979, -52.50301187849567], - [-59.04427782214608, -52.495402650795825], - [-59.04066074761231, -52.487538948672174], - [-59.03832483311475, -52.47949662496506], - [-59.03729189604848, -52.471353214365486], - [-59.037571168142264, -52.46318718358906], - [-59.03915923412195, -52.45507717417564], - [-59.042040092478956, -52.44710124526024], - [-59.04618533668858, -52.439336123597194], - [-59.05155445409762, -52.43185646798682], - [-59.058095238641386, -52.42473415505608], - [-59.06574431256431, -52.41803759308379], - [-59.074427751409445, -52.41183107024558], - [-59.08406180571499, -52.406174143283636], - [-59.094553712110944, -52.40112107219045], - [-59.10580258584608, -52.39672030603672], - [-59.11770038619459, -52.393014024577106], - [-59.13013294569025, -52.39003773973814], - [-59.1429810537112, -52.38781996053568], - [-59.15612158458851, -52.38638192438844], - [-59.1694286601329, -52.38573739719403] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from POINT (0.0000000018626451 -0.0000000000582077)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-61.24520650893593, -43.58579503441036], - [-62.43900162590413, -43.7497691803044], - [-63.612493495637935, -43.98526799486243], - [-64.75854728127679, -44.29048284578168], - [-65.8700825921841, -44.66312804387328], - [-66.94006272166334, -45.1004732252497], - [-67.9614737741224, -45.59937659973779], - [-68.92729370338857, -46.15631640527768], - [-69.83045219128213, -46.76741801639982], - [-70.66378326655452, -47.42847443676813], - [-71.41997361090772, -48.13495833299394], - [-72.09151065439988, -48.882024310623756], - [-72.6706358782252, -49.664500770531255], - [-73.14931027864807, -50.476871403171394], - [-73.51920075465131, -51.31324718174949], - [-73.77169828311617, -52.167330620433404], - [-73.89798108443222, -53.03237509921963], - [-73.88913836949948, -53.90114325644239], - [-73.73637229116584, -54.76586983775868], - [-73.43129667883855, -55.61823596017793], - [-72.96634988358412, -56.44936343019421], - [-72.33533402340117, -57.24983936549483], - [-71.53408218355598, -58.00978256805621], - [-70.56123686602989, -58.718963338760304], - [-69.41909630797443, -59.36698696897535], - [-68.11445159665061, -59.94354715854076], - [-66.6593020132534, -60.43874842291802], - [-65.07130869580571, -60.84348608774121], - [-63.373841197634476, -61.14985974334563], - [-61.59550107201298, -61.35158347731795], - [-59.769076979770325, -61.44434744422618], - [-57.92998819038475, -61.4260841620998], - [-56.11438242397838, -61.297101661684735], - [-54.357135124600056, -61.06006358545125], - [-52.69002133019903, -60.71981951054116], - [-51.14028922561234, -60.28311106090644], - [-49.729771998013284, -59.758195045596224], - [-48.474564115067665, -59.15443076016106], - [-47.38519289556456, -58.48187497961913], - [-46.46715720227685, -57.750917958459475], - [-45.72168645238335, -56.97198083003314], - [-45.14658626457788, -56.15528252407841], - [-44.73706796700835, -55.310674728097155], - [-44.48649497754395, -54.44753717268912], - [-44.387011124193485, -53.57472233140239], - [-44.430040299351845, -52.70053774185403], - [-44.60666284083145, -51.832754751180374], - [-44.90788297302482, -50.97863387520219], - [-45.324805438658956, -50.144958652578566], - [-45.84873994638991, -49.33807158107319], - [-46.47125070424038, -48.5639072973302], - [-47.18416610732345, -47.82801955351357], - [-47.97956121781107, -47.13559975539399], - [-48.84972334727718, -46.491485880558855], - [-49.78710896857661, -45.90016151854075], - [-50.78429837575387, -45.36574558456223], - [-51.833952947595336, -44.89197395974785], - [-52.92877850338137, -44.48217489381598], - [-54.061497019491156, -44.13924045137882], - [-55.2248278682477, -43.86559656447767], - [-56.411478731061244, -43.66317434755541], - [-57.61414543189189, -43.5333852208467], - [-58.825519155892074, -43.477102072976976], - [-60.038298892920785, -43.49464819107359], - [-61.24520650893593, -43.58579503441036] - ], - [ - [-59.1429810537112, -52.38781996053568], - [-59.13013294569025, -52.39003773973814], - [-59.11770038619459, -52.393014024577106], - [-59.10580258584608, -52.39672030603672], - [-59.094553712110944, -52.40112107219045], - [-59.08406180571499, -52.406174143283636], - [-59.074427751409445, -52.41183107024558], - [-59.06574431256431, -52.41803759308379], - [-59.058095238641386, -52.42473415505608], - [-59.05155445409762, -52.43185646798682], - [-59.04618533668858, -52.439336123597194], - [-59.042040092478956, -52.44710124526024], - [-59.03915923412195, -52.45507717417564], - [-59.037571168142264, -52.46318718358906], - [-59.03729189604848, -52.471353214365486], - [-59.03832483311475, -52.47949662496506], - [-59.04066074761231, -52.487538948672174], - [-59.04427782214608, -52.495402650795825], - [-59.04914183756979, -52.50301187849567], - [-59.05520647872498, -52.51029319589711], - [-59.06241375998853, -52.51717629724248], - [-59.07069456733568, -52.52359469098489], - [-59.07996931234633, -52.529486347968145], - [-59.09014869232144, -52.534794307148545], - [-59.10113454945126, -52.539467232702386], - [-59.112820820809006, -52.543459916821654], - [-59.12509456985153, -52.546733723028545], - [-59.13783708911096, -52.54925696542863], - [-59.15092506287909, -52.551005219969966], - [-59.1642317779319, -52.55196156447031], - [-59.177628369734414, -52.55211674491189], - [-59.19098509111309, -52.551469266271], - [-59.20417259009765, -52.55002540694027], - [-59.21706318351819, -52.5477991566033], - [-59.22953211300261, -52.54481207822556], - [-59.241458770249146, -52.541093095619], - [-59.2527278788472, -52.53667820881417], - [-59.26323062047682, -52.53161014021919], - [-59.27286569402213, -52.52593791525311], - [-59.2815402969746, -52.519716381802446], - [-59.28917101945945, -52.51300567345666], - [-59.29568464227776, -52.50587062202425], - [-59.30101883149693, -52.49838012531171], - [-59.30512272332469, -52.490606476557], - [-59.307957394246614, -52.4826246622458], - [-59.30949621267497, -52.47451163530008], - [-59.309725069629614, -52.46634557081417], - [-59.30864248723164, -52.458205111623066], - [-59.30625960502348, -52.45016861102354], - [-59.30260004532041, -52.44231337993217], - [-59.297699659936825, -52.43471494565813], - [-59.29160616170672, -52.42744632929708], - [-59.28437864522447, -52.42057734851895], - [-59.276087002163194, -52.41417395222987], - [-59.26681123738075, -52.408297593245116], - [-59.2566406927957, -52.40300464471517], - [-59.24567318670733, -52.398345865610736], - [-59.23401407684473, -52.39436592009533], - [-59.22177525596318, -52.391102955103605], - [-59.209074089262515, -52.3885882399017], - [-59.19603230328524, -52.38684587084007], - [-59.182774836264244, -52.38589254392049], - [-59.1694286601329, -52.38573739719403], - [-59.15612158458851, -52.38638192438844], - [-59.1429810537112, -52.38781996053568] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 18520 meters away from POINT (-5436.058064267971 3138.509586735512)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.121698601708005, -52.35221938878728], - [-59.1483707669824, -52.352539181791855], - [-59.174864956379174, -52.354452308599825], - [-59.200928824878766, -52.35794051703288], - [-59.22631399917205, -52.36297054867728], - [-59.25077836975904, -52.36949444660461], - [-59.274088332830544, -52.37744999898237], - [-59.29602096370069, -52.38676131496918], - [-59.31636610373802, -52.39733952820188], - [-59.334928342990615, -52.40908362210935], - [-59.35152888103252, -52.4218813702365], - [-59.36600724899414, -52.43561038373551], - [-59.37822287629847, -52.450139257187445], - [-59.38805648633034, -52.46532880296285], - [-59.395411306136786, -52.48103336342364], - [-59.40021407631661, -52.49710218942012], - [-59.40241584851922, -52.51338087275744], - [-59.40199255945591, -52.52971281960737], - [-59.39894537203628, -52.54594075123524], - [-59.39330077618356, -52.561908217914066], - [-59.38511044405171, -52.57746111151858], - [-59.374450836751734, -52.59244916204673], - [-59.3614225622759, -52.60672740321651], - [-59.34614948705774, -52.620157592342395], - [-59.3287776064854, -52.63260956991959], - [-59.30947368265184, -52.643962544740546], - [-59.28842366062458, -52.65410629094276], - [-59.26583087749274, -52.662942244140226], - [-59.2419140813369, -52.67038448472035], - [-59.21690528000393, -52.67636059748767], - [-59.19104744209, -52.68081239809494], - [-59.16459207477728, -52.683696518105506], - [-59.13779670507807, -52.68498484206297], - [-59.11092229256151, -52.68466479157966], - [-59.084230602734344, -52.68273945317297], - [-59.05798157088611, -52.67922754835072], - [-59.03243068637424, -52.67416324624244], - [-59.0078264270101, -52.66759582086878], - [-58.98440777242225, -52.65958915690083], - [-58.96240182403855, -52.65022110946301], - [-58.94202155767735, -52.63958272514549], - [-58.92346373271497, -52.627777332894894], - [-58.90690697945177, -52.61491951482181], - [-58.89251008369364, -52.601133968183774], - [-58.880410484761896, -52.586554270859715], - [-58.87072300020584, -52.57132156351448], - [-58.86353878748618, -52.555583162357834], - [-58.858924549881515, -52.53949111692515], - [-58.856921990905285, -52.52320072765201], - [-58.857547518654094, -52.50686903818477], - [-58.86079219878598, -52.49065331737245], - [-58.86662195228274, -52.47470954573185], - [-58.874977991810596, -52.45919092087807], - [-58.88577748837689, -52.44424639598174], - [-58.89891445809545, -52.43001926476255], - [-58.91426085722352, -52.41664580587255], - [-58.93166787221224, -52.40425399877453], - [-58.95096739031223, -52.392962322392755], - [-58.97197363527894, -52.38287864691966], - [-58.99448495191189, -52.37409922821219], - [-59.01828572251772, -52.36670781321734], - [-59.04314839788572, -52.36077486383433], - [-59.06883562498646, -52.35635690556254], - [-59.09510245332768, -52.353496006203315], - [-59.121698601708005, -52.35221938878728] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from POINT (-5436.058064267971 3138.509586735512)" - }, - "geometry": { "type": "Polygon", "coordinates": [[]] } - } - ] -} diff --git a/tests/flightplan/testcases/ip-backtracking-required/2.json b/tests/flightplan/testcases/ip-backtracking-required/2.json deleted file mode 100644 index b7587b079..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/2.json +++ /dev/null @@ -1,349 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "UnsafeIpStrategy", - "prerequisites": [ - { - "requirement": "at least 18520 meters between", - "satisfied": false, - "subject": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - }, - "target": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.1694286601329, -52.38573739719403], - [-59.182774836264244, -52.38589254392049], - [-59.19603230328524, -52.38684587084007], - [-59.209074089262515, -52.3885882399017], - [-59.22177525596318, -52.391102955103605], - [-59.23401407684473, -52.39436592009533], - [-59.24567318670733, -52.398345865610736], - [-59.2566406927957, -52.40300464471517], - [-59.26681123738075, -52.408297593245116], - [-59.276087002163194, -52.41417395222987], - [-59.28437864522447, -52.42057734851895], - [-59.29160616170672, -52.42744632929708], - [-59.297699659936825, -52.43471494565813], - [-59.30260004532041, -52.44231337993217], - [-59.30625960502348, -52.45016861102354], - [-59.30864248723164, -52.458205111623066], - [-59.309725069629614, -52.46634557081417], - [-59.30949621267497, -52.47451163530008], - [-59.307957394246614, -52.4826246622458], - [-59.30512272332469, -52.490606476557], - [-59.30101883149693, -52.49838012531171], - [-59.29568464227776, -52.50587062202425], - [-59.28917101945945, -52.51300567345666], - [-59.2815402969746, -52.519716381802446], - [-59.27286569402213, -52.52593791525311], - [-59.26323062047682, -52.53161014021919], - [-59.2527278788472, -52.53667820881417], - [-59.241458770249146, -52.541093095619], - [-59.22953211300261, -52.54481207822556], - [-59.21706318351819, -52.5477991566033], - [-59.20417259009765, -52.55002540694027], - [-59.19098509111309, -52.551469266271], - [-59.177628369734414, -52.55211674491189], - [-59.1642317779319, -52.55196156447031], - [-59.15092506287909, -52.551005219969966], - [-59.13783708911096, -52.54925696542863], - [-59.12509456985153, -52.546733723028545], - [-59.112820820809006, -52.543459916821654], - [-59.10113454945126, -52.539467232702386], - [-59.09014869232144, -52.534794307148545], - [-59.07996931234633, -52.529486347968145], - [-59.07069456733568, -52.52359469098489], - [-59.06241375998853, -52.51717629724248], - [-59.05520647872498, -52.51029319589711], - [-59.04914183756979, -52.50301187849567], - [-59.04427782214608, -52.495402650795825], - [-59.04066074761231, -52.487538948672174], - [-59.03832483311475, -52.47949662496506], - [-59.03729189604848, -52.471353214365486], - [-59.037571168142264, -52.46318718358906], - [-59.03915923412195, -52.45507717417564], - [-59.042040092478956, -52.44710124526024], - [-59.04618533668858, -52.439336123597194], - [-59.05155445409762, -52.43185646798682], - [-59.058095238641386, -52.42473415505608], - [-59.06574431256431, -52.41803759308379], - [-59.074427751409445, -52.41183107024558], - [-59.08406180571499, -52.406174143283636], - [-59.094553712110944, -52.40112107219045], - [-59.10580258584608, -52.39672030603672], - [-59.11770038619459, -52.393014024577106], - [-59.13013294569025, -52.39003773973814], - [-59.1429810537112, -52.38781996053568], - [-59.15612158458851, -52.38638192438844], - [-59.1694286601329, -52.38573739719403] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-61.24520650893593, -43.58579503441036], - [-62.43900162590413, -43.7497691803044], - [-63.612493495637935, -43.98526799486243], - [-64.75854728127679, -44.29048284578168], - [-65.8700825921841, -44.66312804387328], - [-66.94006272166334, -45.1004732252497], - [-67.9614737741224, -45.59937659973779], - [-68.92729370338857, -46.15631640527768], - [-69.83045219128213, -46.76741801639982], - [-70.66378326655452, -47.42847443676813], - [-71.41997361090772, -48.13495833299394], - [-72.09151065439988, -48.882024310623756], - [-72.6706358782252, -49.664500770531255], - [-73.14931027864807, -50.476871403171394], - [-73.51920075465131, -51.31324718174949], - [-73.77169828311617, -52.167330620433404], - [-73.89798108443222, -53.03237509921963], - [-73.88913836949948, -53.90114325644239], - [-73.73637229116584, -54.76586983775868], - [-73.43129667883855, -55.61823596017793], - [-72.96634988358412, -56.44936343019421], - [-72.33533402340117, -57.24983936549483], - [-71.53408218355598, -58.00978256805621], - [-70.56123686602989, -58.718963338760304], - [-69.41909630797443, -59.36698696897535], - [-68.11445159665061, -59.94354715854076], - [-66.6593020132534, -60.43874842291802], - [-65.07130869580571, -60.84348608774121], - [-63.373841197634476, -61.14985974334563], - [-61.59550107201298, -61.35158347731795], - [-59.769076979770325, -61.44434744422618], - [-57.92998819038475, -61.4260841620998], - [-56.11438242397838, -61.297101661684735], - [-54.357135124600056, -61.06006358545125], - [-52.69002133019903, -60.71981951054116], - [-51.14028922561234, -60.28311106090644], - [-49.729771998013284, -59.758195045596224], - [-48.474564115067665, -59.15443076016106], - [-47.38519289556456, -58.48187497961913], - [-46.46715720227685, -57.750917958459475], - [-45.72168645238335, -56.97198083003314], - [-45.14658626457788, -56.15528252407841], - [-44.73706796700835, -55.310674728097155], - [-44.48649497754395, -54.44753717268912], - [-44.387011124193485, -53.57472233140239], - [-44.430040299351845, -52.70053774185403], - [-44.60666284083145, -51.832754751180374], - [-44.90788297302482, -50.97863387520219], - [-45.324805438658956, -50.144958652578566], - [-45.84873994638991, -49.33807158107319], - [-46.47125070424038, -48.5639072973302], - [-47.18416610732345, -47.82801955351357], - [-47.97956121781107, -47.13559975539399], - [-48.84972334727718, -46.491485880558855], - [-49.78710896857661, -45.90016151854075], - [-50.78429837575387, -45.36574558456223], - [-51.833952947595336, -44.89197395974785], - [-52.92877850338137, -44.48217489381598], - [-54.061497019491156, -44.13924045137882], - [-55.2248278682477, -43.86559656447767], - [-56.411478731061244, -43.66317434755541], - [-57.61414543189189, -43.5333852208467], - [-58.825519155892074, -43.477102072976976], - [-60.038298892920785, -43.49464819107359], - [-61.24520650893593, -43.58579503441036] - ], - [ - [-59.1429810537112, -52.38781996053568], - [-59.13013294569025, -52.39003773973814], - [-59.11770038619459, -52.393014024577106], - [-59.10580258584608, -52.39672030603672], - [-59.094553712110944, -52.40112107219045], - [-59.08406180571499, -52.406174143283636], - [-59.074427751409445, -52.41183107024558], - [-59.06574431256431, -52.41803759308379], - [-59.058095238641386, -52.42473415505608], - [-59.05155445409762, -52.43185646798682], - [-59.04618533668858, -52.439336123597194], - [-59.042040092478956, -52.44710124526024], - [-59.03915923412195, -52.45507717417564], - [-59.037571168142264, -52.46318718358906], - [-59.03729189604848, -52.471353214365486], - [-59.03832483311475, -52.47949662496506], - [-59.04066074761231, -52.487538948672174], - [-59.04427782214608, -52.495402650795825], - [-59.04914183756979, -52.50301187849567], - [-59.05520647872498, -52.51029319589711], - [-59.06241375998853, -52.51717629724248], - [-59.07069456733568, -52.52359469098489], - [-59.07996931234633, -52.529486347968145], - [-59.09014869232144, -52.534794307148545], - [-59.10113454945126, -52.539467232702386], - [-59.112820820809006, -52.543459916821654], - [-59.12509456985153, -52.546733723028545], - [-59.13783708911096, -52.54925696542863], - [-59.15092506287909, -52.551005219969966], - [-59.1642317779319, -52.55196156447031], - [-59.177628369734414, -52.55211674491189], - [-59.19098509111309, -52.551469266271], - [-59.20417259009765, -52.55002540694027], - [-59.21706318351819, -52.5477991566033], - [-59.22953211300261, -52.54481207822556], - [-59.241458770249146, -52.541093095619], - [-59.2527278788472, -52.53667820881417], - [-59.26323062047682, -52.53161014021919], - [-59.27286569402213, -52.52593791525311], - [-59.2815402969746, -52.519716381802446], - [-59.28917101945945, -52.51300567345666], - [-59.29568464227776, -52.50587062202425], - [-59.30101883149693, -52.49838012531171], - [-59.30512272332469, -52.490606476557], - [-59.307957394246614, -52.4826246622458], - [-59.30949621267497, -52.47451163530008], - [-59.309725069629614, -52.46634557081417], - [-59.30864248723164, -52.458205111623066], - [-59.30625960502348, -52.45016861102354], - [-59.30260004532041, -52.44231337993217], - [-59.297699659936825, -52.43471494565813], - [-59.29160616170672, -52.42744632929708], - [-59.28437864522447, -52.42057734851895], - [-59.276087002163194, -52.41417395222987], - [-59.26681123738075, -52.408297593245116], - [-59.2566406927957, -52.40300464471517], - [-59.24567318670733, -52.398345865610736], - [-59.23401407684473, -52.39436592009533], - [-59.22177525596318, -52.391102955103605], - [-59.209074089262515, -52.3885882399017], - [-59.19603230328524, -52.38684587084007], - [-59.182774836264244, -52.38589254392049], - [-59.1694286601329, -52.38573739719403], - [-59.15612158458851, -52.38638192438844], - [-59.1429810537112, -52.38781996053568] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 18520 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.121698601708005, -52.35221938878728], - [-59.1483707669824, -52.352539181791855], - [-59.174864956379174, -52.354452308599825], - [-59.200928824878766, -52.35794051703288], - [-59.22631399917205, -52.36297054867728], - [-59.25077836975904, -52.36949444660461], - [-59.274088332830544, -52.37744999898237], - [-59.29602096370069, -52.38676131496918], - [-59.31636610373802, -52.39733952820188], - [-59.334928342990615, -52.40908362210935], - [-59.35152888103252, -52.4218813702365], - [-59.36600724899414, -52.43561038373551], - [-59.37822287629847, -52.450139257187445], - [-59.38805648633034, -52.46532880296285], - [-59.395411306136786, -52.48103336342364], - [-59.40021407631661, -52.49710218942012], - [-59.40241584851922, -52.51338087275744], - [-59.40199255945591, -52.52971281960737], - [-59.39894537203628, -52.54594075123524], - [-59.39330077618356, -52.561908217914066], - [-59.38511044405171, -52.57746111151858], - [-59.374450836751734, -52.59244916204673], - [-59.3614225622759, -52.60672740321651], - [-59.34614948705774, -52.620157592342395], - [-59.3287776064854, -52.63260956991959], - [-59.30947368265184, -52.643962544740546], - [-59.28842366062458, -52.65410629094276], - [-59.26583087749274, -52.662942244140226], - [-59.2419140813369, -52.67038448472035], - [-59.21690528000393, -52.67636059748767], - [-59.19104744209, -52.68081239809494], - [-59.16459207477728, -52.683696518105506], - [-59.13779670507807, -52.68498484206297], - [-59.11092229256151, -52.68466479157966], - [-59.084230602734344, -52.68273945317297], - [-59.05798157088611, -52.67922754835072], - [-59.03243068637424, -52.67416324624244], - [-59.0078264270101, -52.66759582086878], - [-58.98440777242225, -52.65958915690083], - [-58.96240182403855, -52.65022110946301], - [-58.94202155767735, -52.63958272514549], - [-58.92346373271497, -52.627777332894894], - [-58.90690697945177, -52.61491951482181], - [-58.89251008369364, -52.601133968183774], - [-58.880410484761896, -52.586554270859715], - [-58.87072300020584, -52.57132156351448], - [-58.86353878748618, -52.555583162357834], - [-58.858924549881515, -52.53949111692515], - [-58.856921990905285, -52.52320072765201], - [-58.857547518654094, -52.50686903818477], - [-58.86079219878598, -52.49065331737245], - [-58.86662195228274, -52.47470954573185], - [-58.874977991810596, -52.45919092087807], - [-58.88577748837689, -52.44424639598174], - [-58.89891445809545, -52.43001926476255], - [-58.91426085722352, -52.41664580587255], - [-58.93166787221224, -52.40425399877453], - [-58.95096739031223, -52.392962322392755], - [-58.97197363527894, -52.38287864691966], - [-58.99448495191189, -52.37409922821219], - [-59.01828572251772, -52.36670781321734], - [-59.04314839788572, -52.36077486383433], - [-59.06883562498646, -52.35635690556254], - [-59.09510245332768, -52.353496006203315], - [-59.121698601708005, -52.35221938878728] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 6277.019173472721 meters away from target" - }, - "geometry": { "type": "Polygon", "coordinates": [[]] } - } - ] -} diff --git a/tests/flightplan/testcases/ip-backtracking-required/3.json b/tests/flightplan/testcases/ip-backtracking-required/3.json deleted file mode 100644 index a710e64ed..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/3.json +++ /dev/null @@ -1,337 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { "name": "SafeBackTrackingIpStrategy", "prerequisites": [] }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.1694286601329, -52.38573739719403], - [-59.182774836264244, -52.38589254392049], - [-59.19603230328524, -52.38684587084007], - [-59.209074089262515, -52.3885882399017], - [-59.22177525596318, -52.391102955103605], - [-59.23401407684473, -52.39436592009533], - [-59.24567318670733, -52.398345865610736], - [-59.2566406927957, -52.40300464471517], - [-59.26681123738075, -52.408297593245116], - [-59.276087002163194, -52.41417395222987], - [-59.28437864522447, -52.42057734851895], - [-59.29160616170672, -52.42744632929708], - [-59.297699659936825, -52.43471494565813], - [-59.30260004532041, -52.44231337993217], - [-59.30625960502348, -52.45016861102354], - [-59.30864248723164, -52.458205111623066], - [-59.309725069629614, -52.46634557081417], - [-59.30949621267497, -52.47451163530008], - [-59.307957394246614, -52.4826246622458], - [-59.30512272332469, -52.490606476557], - [-59.30101883149693, -52.49838012531171], - [-59.29568464227776, -52.50587062202425], - [-59.28917101945945, -52.51300567345666], - [-59.2815402969746, -52.519716381802446], - [-59.27286569402213, -52.52593791525311], - [-59.26323062047682, -52.53161014021919], - [-59.2527278788472, -52.53667820881417], - [-59.241458770249146, -52.541093095619], - [-59.22953211300261, -52.54481207822556], - [-59.21706318351819, -52.5477991566033], - [-59.20417259009765, -52.55002540694027], - [-59.19098509111309, -52.551469266271], - [-59.177628369734414, -52.55211674491189], - [-59.1642317779319, -52.55196156447031], - [-59.15092506287909, -52.551005219969966], - [-59.13783708911096, -52.54925696542863], - [-59.12509456985153, -52.546733723028545], - [-59.112820820809006, -52.543459916821654], - [-59.10113454945126, -52.539467232702386], - [-59.09014869232144, -52.534794307148545], - [-59.07996931234633, -52.529486347968145], - [-59.07069456733568, -52.52359469098489], - [-59.06241375998853, -52.51717629724248], - [-59.05520647872498, -52.51029319589711], - [-59.04914183756979, -52.50301187849567], - [-59.04427782214608, -52.495402650795825], - [-59.04066074761231, -52.487538948672174], - [-59.03832483311475, -52.47949662496506], - [-59.03729189604848, -52.471353214365486], - [-59.037571168142264, -52.46318718358906], - [-59.03915923412195, -52.45507717417564], - [-59.042040092478956, -52.44710124526024], - [-59.04618533668858, -52.439336123597194], - [-59.05155445409762, -52.43185646798682], - [-59.058095238641386, -52.42473415505608], - [-59.06574431256431, -52.41803759308379], - [-59.074427751409445, -52.41183107024558], - [-59.08406180571499, -52.406174143283636], - [-59.094553712110944, -52.40112107219045], - [-59.10580258584608, -52.39672030603672], - [-59.11770038619459, -52.393014024577106], - [-59.13013294569025, -52.39003773973814], - [-59.1429810537112, -52.38781996053568], - [-59.15612158458851, -52.38638192438844], - [-59.1694286601329, -52.38573739719403] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 18520 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.121698601708005, -52.35221938878728], - [-59.1483707669824, -52.352539181791855], - [-59.174864956379174, -52.354452308599825], - [-59.200928824878766, -52.35794051703288], - [-59.22631399917205, -52.36297054867728], - [-59.25077836975904, -52.36949444660461], - [-59.274088332830544, -52.37744999898237], - [-59.29602096370069, -52.38676131496918], - [-59.31636610373802, -52.39733952820188], - [-59.334928342990615, -52.40908362210935], - [-59.35152888103252, -52.4218813702365], - [-59.36600724899414, -52.43561038373551], - [-59.37822287629847, -52.450139257187445], - [-59.38805648633034, -52.46532880296285], - [-59.395411306136786, -52.48103336342364], - [-59.40021407631661, -52.49710218942012], - [-59.40241584851922, -52.51338087275744], - [-59.40199255945591, -52.52971281960737], - [-59.39894537203628, -52.54594075123524], - [-59.39330077618356, -52.561908217914066], - [-59.38511044405171, -52.57746111151858], - [-59.374450836751734, -52.59244916204673], - [-59.3614225622759, -52.60672740321651], - [-59.34614948705774, -52.620157592342395], - [-59.3287776064854, -52.63260956991959], - [-59.30947368265184, -52.643962544740546], - [-59.28842366062458, -52.65410629094276], - [-59.26583087749274, -52.662942244140226], - [-59.2419140813369, -52.67038448472035], - [-59.21690528000393, -52.67636059748767], - [-59.19104744209, -52.68081239809494], - [-59.16459207477728, -52.683696518105506], - [-59.13779670507807, -52.68498484206297], - [-59.11092229256151, -52.68466479157966], - [-59.084230602734344, -52.68273945317297], - [-59.05798157088611, -52.67922754835072], - [-59.03243068637424, -52.67416324624244], - [-59.0078264270101, -52.66759582086878], - [-58.98440777242225, -52.65958915690083], - [-58.96240182403855, -52.65022110946301], - [-58.94202155767735, -52.63958272514549], - [-58.92346373271497, -52.627777332894894], - [-58.90690697945177, -52.61491951482181], - [-58.89251008369364, -52.601133968183774], - [-58.880410484761896, -52.586554270859715], - [-58.87072300020584, -52.57132156351448], - [-58.86353878748618, -52.555583162357834], - [-58.858924549881515, -52.53949111692515], - [-58.856921990905285, -52.52320072765201], - [-58.857547518654094, -52.50686903818477], - [-58.86079219878598, -52.49065331737245], - [-58.86662195228274, -52.47470954573185], - [-58.874977991810596, -52.45919092087807], - [-58.88577748837689, -52.44424639598174], - [-58.89891445809545, -52.43001926476255], - [-58.91426085722352, -52.41664580587255], - [-58.93166787221224, -52.40425399877453], - [-58.95096739031223, -52.392962322392755], - [-58.97197363527894, -52.38287864691966], - [-58.99448495191189, -52.37409922821219], - [-59.01828572251772, -52.36670781321734], - [-59.04314839788572, -52.36077486383433], - [-59.06883562498646, -52.35635690556254], - [-59.09510245332768, -52.353496006203315], - [-59.121698601708005, -52.35221938878728] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 55560 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-62.43900162590413, -43.7497691803044], - [-63.612493495637935, -43.98526799486243], - [-64.75854728127679, -44.29048284578168], - [-65.8700825921841, -44.66312804387328], - [-66.94006272166334, -45.1004732252497], - [-67.9614737741224, -45.59937659973779], - [-68.92729370338857, -46.15631640527768], - [-69.83045219128213, -46.76741801639982], - [-70.66378326655452, -47.42847443676813], - [-71.41997361090772, -48.13495833299394], - [-72.09151065439988, -48.882024310623756], - [-72.6706358782252, -49.664500770531255], - [-73.14931027864807, -50.476871403171394], - [-73.51920075465131, -51.31324718174949], - [-73.77169828311617, -52.167330620433404], - [-73.89798108443222, -53.03237509921963], - [-73.88913836949948, -53.90114325644239], - [-73.73637229116584, -54.76586983775868], - [-73.43129667883855, -55.61823596017793], - [-72.96634988358412, -56.44936343019421], - [-72.33533402340117, -57.24983936549483], - [-71.53408218355598, -58.00978256805621], - [-70.56123686602989, -58.718963338760304], - [-69.41909630797443, -59.36698696897535], - [-68.11445159665061, -59.94354715854076], - [-66.6593020132534, -60.43874842291802], - [-65.07130869580571, -60.84348608774121], - [-63.373841197634476, -61.14985974334563], - [-61.59550107201298, -61.35158347731795], - [-59.769076979770325, -61.44434744422618], - [-57.92998819038475, -61.4260841620998], - [-56.11438242397838, -61.297101661684735], - [-54.357135124600056, -61.06006358545125], - [-52.69002133019903, -60.71981951054116], - [-51.14028922561234, -60.28311106090644], - [-49.729771998013284, -59.758195045596224], - [-48.474564115067665, -59.15443076016106], - [-47.38519289556456, -58.48187497961913], - [-46.46715720227685, -57.750917958459475], - [-45.72168645238335, -56.97198083003314], - [-45.14658626457788, -56.15528252407841], - [-44.73706796700835, -55.310674728097155], - [-44.48649497754395, -54.44753717268912], - [-44.387011124193485, -53.57472233140239], - [-44.430040299351845, -52.70053774185403], - [-44.60666284083145, -51.832754751180374], - [-44.90788297302482, -50.97863387520219], - [-45.324805438658956, -50.144958652578566], - [-45.84873994638991, -49.33807158107319], - [-46.47125070424038, -48.5639072973302], - [-47.18416610732345, -47.82801955351357], - [-47.97956121781107, -47.13559975539399], - [-48.84972334727718, -46.491485880558855], - [-49.78710896857661, -45.90016151854075], - [-50.78429837575387, -45.36574558456223], - [-51.833952947595336, -44.89197395974785], - [-52.92877850338137, -44.48217489381598], - [-54.061497019491156, -44.13924045137882], - [-55.2248278682477, -43.86559656447767], - [-56.411478731061244, -43.66317434755541], - [-57.61414543189189, -43.5333852208467], - [-58.825519155892074, -43.477102072976976], - [-60.038298892920785, -43.49464819107359], - [-61.24520650893593, -43.58579503441036], - [-62.43900162590413, -43.7497691803044] - ], - [ - [-59.02670926455631, -52.02322706672986], - [-58.94846436816389, -52.03174156409738], - [-58.871906660077364, -52.04489601629101], - [-58.79775199415883, -52.06256791810524], - [-58.726696014233006, -52.08459242054974], - [-58.65940814539892, -52.11076372487728], - [-58.59652571122557, -52.14083683497079], - [-58.53864821253077, -52.174529658960374], - [-58.48633180646663, -52.21152544864607], - [-58.44008402793213, -52.251475562869736], - [-58.40035879875543, -52.29400253839339], - [-58.367551773463155, -52.33870344909812], - [-58.34199607358005, -52.385153531414204], - [-58.32395846505535, -52.43291005084225], - [-58.313636035349155, -52.48151638124669], - [-58.31115342767712, -52.530506265334544], - [-58.31656068964784, -52.579408221425744], - [-58.329831791788784, -52.62775005834432], - [-58.35086386802238, -52.67506345709821], - [-58.379477224847115, -52.72088857507158], - [-58.41541615868021, -52.76477862583846], - [-58.45835061148724, -52.806304385548614], - [-58.507878683508366, -52.8450585752576], - [-58.56353000874132, -52.88066006770493], - [-58.62476998411564, -52.91275786699832], - [-58.69100482735511, -52.941034810540124], - [-58.761587421839245, -52.96521094440866], - [-58.83582388988461, -52.985046526322826], - [-58.91298081937771, -53.00034461428131], - [-58.99229305323581, -53.010953203940204], - [-59.0729719373784, -53.016766883695276], - [-59.15421391134509, -53.01772798314966], - [-59.235209316902065, -53.013827198011974], - [-59.31515129433457, -53.00510368229698], - [-59.39324463388378, -52.99164460677537], - [-59.46871445105729, -52.973584190716466], - [-59.54081455926231, -52.951102221860666], - [-59.608835421163434, -52.924422087029775], - [-59.672111570991134, -52.89380834263757], - [-59.730028413242955, -52.85956386043405], - [-59.7820283182583, -52.82202658897476], - [-59.82761595138856, -52.781565975464694], - [-59.86636278929016, -52.73857909574113], - [-59.897910793622685, -52.6934865422267], - [-59.921975228571505, -52.646728120743376], - [-59.938346623647064, -52.598758407198694], - [-59.946891896748646, -52.55004221443467], - [-59.947554664230786, -52.501050018085536], - [-59.94035477450023, -52.452253388247684], - [-59.92538710942365, -52.404120471258125], - [-59.90281970356612, -52.35711156303112], - [-59.8728912351072, -52.311674812336435], - [-59.83590794436586, -52.26824208922418], - [-59.792240036419614, -52.22722505059455], - [-59.74231762357511, -52.189011431753826], - [-59.686626261695615, -52.15396158973911], - [-59.62570213187662, -52.12240532127179], - [-59.56012691593694, -52.09463897543482], - [-59.490522410889135, -52.07092287856727], - [-59.41754492418268, -52.05147908642883], - [-59.341879488252886, -52.036489476394244], - [-59.264233929916095, -52.02609419027485], - [-59.18533282754717, -52.020390436309775], - [-59.10591138685995, -52.019431656897986], - [-59.02670926455631, -52.02322706672986] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "safe" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { "description": "solution" }, - "geometry": { - "type": "Point", - "coordinates": [-59.26111511029073, -52.373023244499485] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-backtracking-required/4.json b/tests/flightplan/testcases/ip-backtracking-required/4.json deleted file mode 100644 index 7add4fbc5..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/4.json +++ /dev/null @@ -1,332 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { "name": "UnsafeBackTrackingIpStrategy", "prerequisites": [] }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.1694286601329, -52.38573739719403], - [-59.182774836264244, -52.38589254392049], - [-59.19603230328524, -52.38684587084007], - [-59.209074089262515, -52.3885882399017], - [-59.22177525596318, -52.391102955103605], - [-59.23401407684473, -52.39436592009533], - [-59.24567318670733, -52.398345865610736], - [-59.2566406927957, -52.40300464471517], - [-59.26681123738075, -52.408297593245116], - [-59.276087002163194, -52.41417395222987], - [-59.28437864522447, -52.42057734851895], - [-59.29160616170672, -52.42744632929708], - [-59.297699659936825, -52.43471494565813], - [-59.30260004532041, -52.44231337993217], - [-59.30625960502348, -52.45016861102354], - [-59.30864248723164, -52.458205111623066], - [-59.309725069629614, -52.46634557081417], - [-59.30949621267497, -52.47451163530008], - [-59.307957394246614, -52.4826246622458], - [-59.30512272332469, -52.490606476557], - [-59.30101883149693, -52.49838012531171], - [-59.29568464227776, -52.50587062202425], - [-59.28917101945945, -52.51300567345666], - [-59.2815402969746, -52.519716381802446], - [-59.27286569402213, -52.52593791525311], - [-59.26323062047682, -52.53161014021919], - [-59.2527278788472, -52.53667820881417], - [-59.241458770249146, -52.541093095619], - [-59.22953211300261, -52.54481207822556], - [-59.21706318351819, -52.5477991566033], - [-59.20417259009765, -52.55002540694027], - [-59.19098509111309, -52.551469266271], - [-59.177628369734414, -52.55211674491189], - [-59.1642317779319, -52.55196156447031], - [-59.15092506287909, -52.551005219969966], - [-59.13783708911096, -52.54925696542863], - [-59.12509456985153, -52.546733723028545], - [-59.112820820809006, -52.543459916821654], - [-59.10113454945126, -52.539467232702386], - [-59.09014869232144, -52.534794307148545], - [-59.07996931234633, -52.529486347968145], - [-59.07069456733568, -52.52359469098489], - [-59.06241375998853, -52.51717629724248], - [-59.05520647872498, -52.51029319589711], - [-59.04914183756979, -52.50301187849567], - [-59.04427782214608, -52.495402650795825], - [-59.04066074761231, -52.487538948672174], - [-59.03832483311475, -52.47949662496506], - [-59.03729189604848, -52.471353214365486], - [-59.037571168142264, -52.46318718358906], - [-59.03915923412195, -52.45507717417564], - [-59.042040092478956, -52.44710124526024], - [-59.04618533668858, -52.439336123597194], - [-59.05155445409762, -52.43185646798682], - [-59.058095238641386, -52.42473415505608], - [-59.06574431256431, -52.41803759308379], - [-59.074427751409445, -52.41183107024558], - [-59.08406180571499, -52.406174143283636], - [-59.094553712110944, -52.40112107219045], - [-59.10580258584608, -52.39672030603672], - [-59.11770038619459, -52.393014024577106], - [-59.13013294569025, -52.39003773973814], - [-59.1429810537112, -52.38781996053568], - [-59.15612158458851, -52.38638192438844], - [-59.1694286601329, -52.38573739719403] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 18520 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-59.121698601708005, -52.35221938878728], - [-59.1483707669824, -52.352539181791855], - [-59.174864956379174, -52.354452308599825], - [-59.200928824878766, -52.35794051703288], - [-59.22631399917205, -52.36297054867728], - [-59.25077836975904, -52.36949444660461], - [-59.274088332830544, -52.37744999898237], - [-59.29602096370069, -52.38676131496918], - [-59.31636610373802, -52.39733952820188], - [-59.334928342990615, -52.40908362210935], - [-59.35152888103252, -52.4218813702365], - [-59.36600724899414, -52.43561038373551], - [-59.37822287629847, -52.450139257187445], - [-59.38805648633034, -52.46532880296285], - [-59.395411306136786, -52.48103336342364], - [-59.40021407631661, -52.49710218942012], - [-59.40241584851922, -52.51338087275744], - [-59.40199255945591, -52.52971281960737], - [-59.39894537203628, -52.54594075123524], - [-59.39330077618356, -52.561908217914066], - [-59.38511044405171, -52.57746111151858], - [-59.374450836751734, -52.59244916204673], - [-59.3614225622759, -52.60672740321651], - [-59.34614948705774, -52.620157592342395], - [-59.3287776064854, -52.63260956991959], - [-59.30947368265184, -52.643962544740546], - [-59.28842366062458, -52.65410629094276], - [-59.26583087749274, -52.662942244140226], - [-59.2419140813369, -52.67038448472035], - [-59.21690528000393, -52.67636059748767], - [-59.19104744209, -52.68081239809494], - [-59.16459207477728, -52.683696518105506], - [-59.13779670507807, -52.68498484206297], - [-59.11092229256151, -52.68466479157966], - [-59.084230602734344, -52.68273945317297], - [-59.05798157088611, -52.67922754835072], - [-59.03243068637424, -52.67416324624244], - [-59.0078264270101, -52.66759582086878], - [-58.98440777242225, -52.65958915690083], - [-58.96240182403855, -52.65022110946301], - [-58.94202155767735, -52.63958272514549], - [-58.92346373271497, -52.627777332894894], - [-58.90690697945177, -52.61491951482181], - [-58.89251008369364, -52.601133968183774], - [-58.880410484761896, -52.586554270859715], - [-58.87072300020584, -52.57132156351448], - [-58.86353878748618, -52.555583162357834], - [-58.858924549881515, -52.53949111692515], - [-58.856921990905285, -52.52320072765201], - [-58.857547518654094, -52.50686903818477], - [-58.86079219878598, -52.49065331737245], - [-58.86662195228274, -52.47470954573185], - [-58.874977991810596, -52.45919092087807], - [-58.88577748837689, -52.44424639598174], - [-58.89891445809545, -52.43001926476255], - [-58.91426085722352, -52.41664580587255], - [-58.93166787221224, -52.40425399877453], - [-58.95096739031223, -52.392962322392755], - [-58.97197363527894, -52.38287864691966], - [-58.99448495191189, -52.37409922821219], - [-59.01828572251772, -52.36670781321734], - [-59.04314839788572, -52.36077486383433], - [-59.06883562498646, -52.35635690556254], - [-59.09510245332768, -52.353496006203315], - [-59.121698601708005, -52.35221938878728] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 55560 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [-62.43900162590413, -43.7497691803044], - [-63.612493495637935, -43.98526799486243], - [-64.75854728127679, -44.29048284578168], - [-65.8700825921841, -44.66312804387328], - [-66.94006272166334, -45.1004732252497], - [-67.9614737741224, -45.59937659973779], - [-68.92729370338857, -46.15631640527768], - [-69.83045219128213, -46.76741801639982], - [-70.66378326655452, -47.42847443676813], - [-71.41997361090772, -48.13495833299394], - [-72.09151065439988, -48.882024310623756], - [-72.6706358782252, -49.664500770531255], - [-73.14931027864807, -50.476871403171394], - [-73.51920075465131, -51.31324718174949], - [-73.77169828311617, -52.167330620433404], - [-73.89798108443222, -53.03237509921963], - [-73.88913836949948, -53.90114325644239], - [-73.73637229116584, -54.76586983775868], - [-73.43129667883855, -55.61823596017793], - [-72.96634988358412, -56.44936343019421], - [-72.33533402340117, -57.24983936549483], - [-71.53408218355598, -58.00978256805621], - [-70.56123686602989, -58.718963338760304], - [-69.41909630797443, -59.36698696897535], - [-68.11445159665061, -59.94354715854076], - [-66.6593020132534, -60.43874842291802], - [-65.07130869580571, -60.84348608774121], - [-63.373841197634476, -61.14985974334563], - [-61.59550107201298, -61.35158347731795], - [-59.769076979770325, -61.44434744422618], - [-57.92998819038475, -61.4260841620998], - [-56.11438242397838, -61.297101661684735], - [-54.357135124600056, -61.06006358545125], - [-52.69002133019903, -60.71981951054116], - [-51.14028922561234, -60.28311106090644], - [-49.729771998013284, -59.758195045596224], - [-48.474564115067665, -59.15443076016106], - [-47.38519289556456, -58.48187497961913], - [-46.46715720227685, -57.750917958459475], - [-45.72168645238335, -56.97198083003314], - [-45.14658626457788, -56.15528252407841], - [-44.73706796700835, -55.310674728097155], - [-44.48649497754395, -54.44753717268912], - [-44.387011124193485, -53.57472233140239], - [-44.430040299351845, -52.70053774185403], - [-44.60666284083145, -51.832754751180374], - [-44.90788297302482, -50.97863387520219], - [-45.324805438658956, -50.144958652578566], - [-45.84873994638991, -49.33807158107319], - [-46.47125070424038, -48.5639072973302], - [-47.18416610732345, -47.82801955351357], - [-47.97956121781107, -47.13559975539399], - [-48.84972334727718, -46.491485880558855], - [-49.78710896857661, -45.90016151854075], - [-50.78429837575387, -45.36574558456223], - [-51.833952947595336, -44.89197395974785], - [-52.92877850338137, -44.48217489381598], - [-54.061497019491156, -44.13924045137882], - [-55.2248278682477, -43.86559656447767], - [-56.411478731061244, -43.66317434755541], - [-57.61414543189189, -43.5333852208467], - [-58.825519155892074, -43.477102072976976], - [-60.038298892920785, -43.49464819107359], - [-61.24520650893593, -43.58579503441036], - [-62.43900162590413, -43.7497691803044] - ], - [ - [-59.02670926455631, -52.02322706672986], - [-58.94846436816389, -52.03174156409738], - [-58.871906660077364, -52.04489601629101], - [-58.79775199415883, -52.06256791810524], - [-58.726696014233006, -52.08459242054974], - [-58.65940814539892, -52.11076372487728], - [-58.59652571122557, -52.14083683497079], - [-58.53864821253077, -52.174529658960374], - [-58.48633180646663, -52.21152544864607], - [-58.44008402793213, -52.251475562869736], - [-58.40035879875543, -52.29400253839339], - [-58.367551773463155, -52.33870344909812], - [-58.34199607358005, -52.385153531414204], - [-58.32395846505535, -52.43291005084225], - [-58.313636035349155, -52.48151638124669], - [-58.31115342767712, -52.530506265334544], - [-58.31656068964784, -52.579408221425744], - [-58.329831791788784, -52.62775005834432], - [-58.35086386802238, -52.67506345709821], - [-58.379477224847115, -52.72088857507158], - [-58.41541615868021, -52.76477862583846], - [-58.45835061148724, -52.806304385548614], - [-58.507878683508366, -52.8450585752576], - [-58.56353000874132, -52.88066006770493], - [-58.62476998411564, -52.91275786699832], - [-58.69100482735511, -52.941034810540124], - [-58.761587421839245, -52.96521094440866], - [-58.83582388988461, -52.985046526322826], - [-58.91298081937771, -53.00034461428131], - [-58.99229305323581, -53.010953203940204], - [-59.0729719373784, -53.016766883695276], - [-59.15421391134509, -53.01772798314966], - [-59.235209316902065, -53.013827198011974], - [-59.31515129433457, -53.00510368229698], - [-59.39324463388378, -52.99164460677537], - [-59.46871445105729, -52.973584190716466], - [-59.54081455926231, -52.951102221860666], - [-59.608835421163434, -52.924422087029775], - [-59.672111570991134, -52.89380834263757], - [-59.730028413242955, -52.85956386043405], - [-59.7820283182583, -52.82202658897476], - [-59.82761595138856, -52.781565975464694], - [-59.86636278929016, -52.73857909574113], - [-59.897910793622685, -52.6934865422267], - [-59.921975228571505, -52.646728120743376], - [-59.938346623647064, -52.598758407198694], - [-59.946891896748646, -52.55004221443467], - [-59.947554664230786, -52.501050018085536], - [-59.94035477450023, -52.452253388247684], - [-59.92538710942365, -52.404120471258125], - [-59.90281970356612, -52.35711156303112], - [-59.8728912351072, -52.311674812336435], - [-59.83590794436586, -52.26824208922418], - [-59.792240036419614, -52.22722505059455], - [-59.74231762357511, -52.189011431753826], - [-59.686626261695615, -52.15396158973911], - [-59.62570213187662, -52.12240532127179], - [-59.56012691593694, -52.09463897543482], - [-59.490522410889135, -52.07092287856727], - [-59.41754492418268, -52.05147908642883], - [-59.341879488252886, -52.036489476394244], - [-59.264233929916095, -52.02609419027485], - [-59.18533282754717, -52.020390436309775], - [-59.10591138685995, -52.019431656897986], - [-59.02670926455631, -52.02322706672986] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "solution" }, - "geometry": { - "type": "Point", - "coordinates": [-59.26111511029073, -52.373023244499485] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-backtracking-required/solver.json b/tests/flightplan/testcases/ip-backtracking-required/solver.json deleted file mode 100644 index d7770b934..000000000 --- a/tests/flightplan/testcases/ip-backtracking-required/solver.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "IpSolver", - "terrain": "Falklands", - "doctrine": "coldwar" - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [-59.17351849883801, -52.46892777233296] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [-59.12970828579045, -52.51860490233211] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { "type": "MultiPolygon", "coordinates": [] } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/0.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/0.json deleted file mode 100644 index a7cda11d6..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/0.json +++ /dev/null @@ -1,1303 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "SafeIpStrategy", - "prerequisites": [ - { - "requirement": "is safe", - "satisfied": false, - "subject": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "requirement": "at least 9260 meters between", - "satisfied": true, - "subject": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - }, - "target": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.26736233944865, 45.212832001107486], - [34.25579740516746, 45.21255839036951], - [34.244326428551396, 45.211483696916154], - [34.23306035341517, 45.20961831000684], - [34.22210811766503, 45.20698026544365], - [34.21157558717508, 45.20359506911417], - [34.20156452118371, 45.19949544747085], - [34.19217157975917, 45.194721027502304], - [34.183487383378, 45.189317949469306], - [34.17559563403959, 45.18333841635551], - [34.16857230661418, 45.17684018461397], - [34.162484918304095, 45.16988600136729], - [34.157391883200646, 45.16254299373665], - [34.153341957958176, 45.15488201642783], - [34.15037378359587, 45.14697696408575], - [34.14851552739211, 45.13890405524209], - [34.147784627771046, 45.13074109491936], - [34.14818764400937, 45.12256672311945], - [34.14972021152702, 45.11445965651546], - [34.152367102480945, 45.10649793068264], - [34.15610239036614, 45.09875815015007], - [34.16088971635356, 45.0913147534311], - [34.166682654167374, 45.0842393000012], - [34.173425169431205, 45.07759978593913], - [34.18105216860053, 45.071459994636875], - [34.18949013184899, 45.065878888618094], - [34.198657823593905, 45.06091004808918], - [34.208467073732066, 45.056601161387114], - [34.218823622111806, 45.05299357198603], - [34.229628018291784, 45.050121886187725], - [34.24077656823069, 45.048013645053835], - [34.252162319213916, 45.04668906354247], - [34.263676074053144, 45.046160839197206], - [34.27520742539138, 45.04643403210431], - [34.28664580080811, 45.04750601718975], - [34.29788150934732, 45.04936650927699], - [34.308806780083216, 45.05199766067219], - [34.31931678339612, 45.055374230391905], - [34.329310625752726, 45.05946382350324], - [34.33869230897222, 45.06422719841171], - [34.347371645212995, 45.06961863931436], - [34.35526511923397, 45.075586390437], - [34.36229668987163, 45.08207314810148], - [34.36839852312876, 45.0890166061257], - [34.37351164979367, 45.096350049549834], - [34.37758654110053, 45.10400299121158], - [34.3805835966, 45.11190184526771], - [34.38247353913498, 45.11997063137987], - [34.38323771260493, 45.12813170295747], - [34.38286827905201, 45.136306492580964], - [34.38136831250716, 45.14441626752098], - [34.37875178798923, 45.15238288812422], - [34.375043465047284, 45.16012956176131], - [34.370278666266756, 45.1675815850243], - [34.36450295221384, 45.17466706692823], - [34.35777169535828, 45.181317626009054], - [34.35014955657871, 45.1874690544232], - [34.341709868905255, 45.19306194244042], - [34.332533934174606, 45.198042257078306], - [34.32271023925041, 45.20236186905445], - [34.31233359938021, 45.20597902272556], - [34.301504237105995, 45.20885874423665], - [34.290326805903796, 45.21097318371445], - [34.27890936838613, 45.21230188799866], - [34.26736233944865, 45.212832001107486] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 15950.796923186528 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [31.543677298228317, 53.94963604274752], - [30.109451949386376, 53.70926634487305], - [28.742883155610553, 53.37102777917536], - [27.46389462890607, 52.940752134787544], - [26.289149201436246, 52.42558296236213], - [25.2317755655535, 51.833680466439375], - [24.301356999465547, 51.1739227661556], - [23.504133160058522, 50.455625832669995], - [22.84335144921626, 49.6882979589566], - [22.319703234680226, 48.88143770394306], - [21.93178847958037, 48.044378075054695], - [21.676565556460687, 47.18617493458924], - [21.549757332469532, 46.31553441956308], - [21.546197458388484, 45.44077240823435], - [21.660110927788, 44.569798443987956], - [21.885330130416587, 43.71011669872251], - [22.215452128337056, 42.86883722452818], - [22.643945309246273, 42.052691678009296], - [23.164214525369015, 41.268048754360905], - [23.769633829388166, 40.52092564797081], - [24.453555363945533, 39.81699291568661], - [25.2093021139904, 39.16157113597788], - [26.03015125198358, 38.55961872054667], - [26.909313778134845, 38.01571113288901], - [27.83991511569523, 37.5340125827803], - [28.814980273384933, 37.118241969710056], - [29.82742613445757, 36.77163540753071], - [30.870062381268912, 36.49690803964221], - [31.9356015349922, 36.29621801526448], - [33.016677616846714, 36.17113542046924], - [34.10587206698068, 36.122618638708744], - [35.195744843286555, 36.15100007372277], - [36.27886811579418, 36.25598244628238], - [37.34785971226055, 36.436646039778864], - [38.39541347764873, 36.691466396894334], - [39.414323981954404, 37.018341143643624], - [40.39750352228982, 37.41462391488392], - [41.337990073220546, 37.87716283824222], - [42.22894569074836, 38.40234074051216], - [43.06364581567034, 38.98611418663667], - [43.8354609045657, 39.62404863842676], - [44.53783280852223, 40.31134740266671], - [45.164249304552754, 41.04287259045077], - [45.70822116070428, 41.81315699317169], - [46.16326708929034, 42.616406561331345], - [46.52291291603217, 43.44649402465259], - [46.780712248668415, 44.296945100310985], - [46.93029680783726, 45.160919693130595], - [46.965465259566614, 46.03119149255079], - [46.88031964092552, 46.90013040448395], - [46.66945795605362, 47.75969329008944], - [46.32822976485015, 48.601429449303446], - [45.853058007334035, 49.416508060652305], - [45.2418242929135, 50.19577517514014], - [44.49430597505506, 50.929847588985695], - [43.61264150674945, 51.60924965704153], - [42.60178663134066, 52.224596522651815], - [41.46990990648969, 52.766823101310656], - [40.22866525041226, 53.227452493221286], - [38.893276033141, 53.598890766464685], - [37.48237406067705, 53.87472823120316], - [36.01756014381054, 54.05002187596711], - [34.52268957103872, 54.121531203967244], - [33.022929636113126, 54.08788160553906], - [31.543677298228317, 53.94963604274752] - ], - [ - [34.28861316397455, 45.272130392648755], - [34.30830007918945, 45.26983905162751], - [34.327571804168144, 45.26619294328286], - [34.34624149762827, 45.26122745004272], - [34.364128286877616, 45.25499074011357], - [34.38105905128238, 45.24754329001464], - [34.39687012272915, 45.23895728602419], - [34.41140888541706, 45.229315910942596], - [34.42453525867446, 45.21871252375587], - [34.436123048042454, 45.20724974085805], - [34.44606115157486, 45.19503842845324], - [34.454254610134385, 45.182196616595895], - [34.46062549238355, 45.16884834603486], - [34.465113607141376, 45.15512245959911], - [34.46767703776809, 45.141151350297626], - [34.46829249522022, 45.127069678603554], - [34.46695548835728, 45.11301307155556], - [34.46368031195521, 45.09911681634077], - [34.458499854668645, 45.085514560930214], - [34.45146523086756, 45.07233703412435], - [34.44264524184112, 45.059710797043216], - [34.432125673303425, 45.04775703766737], - [34.42000843744777, 45.03659041951562], - [34.406410568976, 45.02631799493632], - [34.39146308557885, 45.01703819280597], - [34.37530972426567, 45.008839889674235], - [34.35810556574256, 45.00180157258149], - [34.34001555972386, 44.9959906009078], - [34.32121296464013, 44.99146257370082], - [34.301877715684206, 44.98826080797966], - [34.28219473552208, 44.98641593252975], - [34.26235220229539, 44.98594560069637], - [34.24253978976057, 44.98685432465702], - [34.22294689455304, 44.98913343261177], - [34.20376086563329, 44.992761149281165], - [34.18516525096901, 44.99770279904813], - [34.16733807643089, 45.00391113003037], - [34.150450171728366, 45.0113267563275], - [34.13466355798123, 45.01987871465802], - [34.120129911208124, 45.02948513059309], - [34.10698911560803, 45.04005398861077], - [34.095367920007305, 45.05148399924439], - [34.085378710236725, 45.063665555688864], - [34.07711840948087, 45.07648177136557], - [34.07066751780025, 45.08980958913961], - [34.06608930105789, 45.1035209521393], - [34.06342913838161, 45.11748402545735], - [34.06271403605982, 45.13156445742292], - [34.06395231440043, 45.14562666863581], - [34.0671334725843, 45.15953515655316], - [34.0722282349224, 45.17315580312883], - [34.079188780190364, 45.18635717282915], - [34.087949153880565, 45.19901178829802], - [34.0984258612984, 45.21099737102113], - [34.11051863746004, 45.22219803455216], - [34.12411138774946, 45.23250541821389], - [34.13907329129383, 45.24181974967557], - [34.155260057050576, 45.25005082543541], - [34.17251532070137, 45.25711889899864], - [34.19067216865369, 45.26295546743169], - [34.20955477379388, 45.26750394798484], - [34.22898012615196, 45.2707202375966], - [34.248759840358034, 45.27257314931062], - [34.26870202072193, 45.27304472093657], - [34.28861316397455, 45.272130392648755] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 9260 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.218693248367934, 45.07345742850839], - [34.207156609034314, 45.07317858385598], - [34.19571442232239, 45.072098678335216], - [34.18447735113889, 45.07022815157965], - [34.17355405050042, 45.0675850888894], - [34.163050104272344, 45.06419504429736], - [34.1530669934107, 45.06009079059198], - [34.143701106223666, 45.05531199885625], - [34.135042800665076, 45.04990485079897], - [34.12717552805298, 45.04392158783178], - [34.12017502688297, 45.03742000147535], - [34.114108594590014, 45.03046287025475], - [34.10903444421855, 45.02311734876112], - [34.105001152001904, 45.01545431500847], - [34.102047200844716, 45.007547682598556], - [34.1002006236593, 44.99947368451849], - [34.099478749444835, 44.99131013563475], - [34.09988805392992, 44.98313568111157], - [34.10142411553777, 44.975029038072364], - [34.10407167639184, 44.96706823783931], - [34.10780480706729, 44.95932987603245], - [34.112587172821854, 44.95188837768562], - [34.11837239811455, 44.9448152843467], - [34.12510452535057, 44.93817856987773], - [34.132718562978994, 44.932041991359], - [34.1411411173231, 44.92646448113585], - [34.150291101841326, 44.92149958563124], - [34.160080516903854, 44.91719495608641], - [34.170415292625854, 44.91359189589044], - [34.181196186823364, 44.91072496862194], - [34.192319729752214, 44.90862167035846], - [34.20367920695263, 44.90730216921416], - [34.215165671252784, 44.906779114451105], - [34.226668974780914, 44.90705751687676], - [34.23807881169875, 44.908134701596275], - [34.24928576229671, 44.91000033353673], - [34.2601823290844, 44.91263651550597], - [34.270663955567315, 44.91601795789691], - [34.280630018522984, 44.92011221850257], - [34.28998478477755, 44.92488001027244], - [34.298638323736945, 44.93027557422257], - [34.306507367246816, 44.93624711411307], - [34.31351610874251, 44.94273728893414], - [34.319596934105235, 44.949683758697766], - [34.324691077163955, 44.957019778523744], - [34.32874919337364, 44.964674835538204], - [34.33173184585923, 44.97257532267728], - [34.33360989873961, 44.980645243109905], - [34.3343648134337, 44.98880693866899], - [34.33398884449988, 44.99698183541149], - [34.332485132462814, 45.0050911992202], - [34.32986769203591, 45.0130568942171], - [34.326161295141894, 45.02080213668199], - [34.32140124916276, 45.02825223716482], - [34.31563307190129, 45.035335323546164], - [34.308912065798914, 45.04198303794021], - [34.30130279501616, 45.04813120054805], - [34.29287847002852, 45.053720433855304], - [34.28372024540792, 45.05869674092705], - [34.273916437434, 45.06301203198011], - [34.263561669094074, 45.066624593906724], - [34.25275595087326, 45.069499497978484], - [34.24160370649074, 45.07160894157011], - [34.2302127533942, 45.072932520402624], - [34.218693248367934, 45.07345742850839] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 12964 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.22898012615196, 45.2707202375966], - [34.20955477379388, 45.26750394798484], - [34.19067216865369, 45.26295546743169], - [34.17251532070137, 45.25711889899864], - [34.155260057050576, 45.25005082543541], - [34.13907329129383, 45.24181974967557], - [34.12411138774946, 45.23250541821389], - [34.11051863746004, 45.22219803455216], - [34.0984258612984, 45.21099737102113], - [34.087949153880565, 45.19901178829802], - [34.079188780190364, 45.18635717282915], - [34.0722282349224, 45.17315580312883], - [34.0671334725843, 45.15953515655316], - [34.06395231440043, 45.14562666863581], - [34.06271403605982, 45.13156445742292], - [34.06342913838161, 45.11748402545735], - [34.06608930105789, 45.1035209521393], - [34.07066751780025, 45.08980958913961], - [34.07711840948087, 45.07648177136557], - [34.085378710236725, 45.063665555688864], - [34.0870904867032, 45.06157851859213], - [34.09122826806114, 45.06542321762192], - [34.102241916264724, 45.07380307499917], - [34.11436485174799, 45.081376336403636], - [34.127480193708166, 45.08806973801328], - [34.14146132255797, 45.09381850568349], - [34.156173111212475, 45.09856699091037], - [34.15621831564067, 45.09857793292878], - [34.15610239036614, 45.09875815015007], - [34.152367102480945, 45.10649793068264], - [34.14972021152702, 45.11445965651546], - [34.14818764400937, 45.12256672311945], - [34.147784627771046, 45.13074109491936], - [34.14851552739211, 45.13890405524209], - [34.15037378359587, 45.14697696408575], - [34.153341957958176, 45.15488201642783], - [34.157391883200646, 45.16254299373665], - [34.162484918304095, 45.16988600136729], - [34.16857230661418, 45.17684018461397], - [34.17559563403959, 45.18333841635551], - [34.183487383378, 45.189317949469306], - [34.19217157975917, 45.194721027502304], - [34.20156452118371, 45.19949544747085], - [34.21157558717508, 45.20359506911417], - [34.22210811766503, 45.20698026544365], - [34.23306035341517, 45.20961831000684], - [34.244326428551396, 45.211483696916154], - [34.25579740516746, 45.21255839036951], - [34.26736233944865, 45.212832001107486], - [34.27890936838613, 45.21230188799866], - [34.290326805903796, 45.21097318371445], - [34.301504237105995, 45.20885874423665], - [34.31233359938021, 45.20597902272556], - [34.32271023925041, 45.20236186905445], - [34.332533934174606, 45.198042257078306], - [34.341709868905255, 45.19306194244042], - [34.35014955657871, 45.1874690544232], - [34.35777169535828, 45.181317626009054], - [34.36450295221384, 45.17466706692823], - [34.370278666266756, 45.1675815850243], - [34.375043465047284, 45.16012956176131], - [34.37875178798923, 45.15238288812422], - [34.38136831250716, 45.14441626752098], - [34.38286827905201, 45.136306492580964], - [34.38323771260493, 45.12813170295747], - [34.38247353913498, 45.11997063137987], - [34.3805835966, 45.11190184526771], - [34.37758654110053, 45.10400299121158], - [34.37351164979367, 45.096350049549834], - [34.36839852312876, 45.0890166061257], - [34.36229668987163, 45.08207314810148], - [34.35526511923397, 45.075586390437], - [34.347371645212995, 45.06961863931436], - [34.34162193326194, 45.066047215653676], - [34.345753011811674, 45.06270726142404], - [34.35515925963138, 45.05339738106913], - [34.363229885564245, 45.04347826716147], - [34.369887653840365, 45.033045728213686], - [34.37506908371292, 45.02220047726584], - [34.37872503597813, 45.01104715270264], - [34.37880497576605, 45.010614228711724], - [34.39146308557885, 45.01703819280597], - [34.406410568976, 45.02631799493632], - [34.42000843744777, 45.03659041951562], - [34.432125673303425, 45.04775703766737], - [34.44264524184112, 45.059710797043216], - [34.45146523086756, 45.07233703412435], - [34.458499854668645, 45.085514560930214], - [34.46368031195521, 45.09911681634077], - [34.46695548835728, 45.11301307155556], - [34.46829249522022, 45.127069678603554], - [34.46767703776809, 45.141151350297626], - [34.465113607141376, 45.15512245959911], - [34.46062549238355, 45.16884834603486], - [34.454254610134385, 45.182196616595895], - [34.44606115157486, 45.19503842845324], - [34.436123048042454, 45.20724974085805], - [34.42453525867446, 45.21871252375587], - [34.41140888541706, 45.229315910942596], - [34.39687012272915, 45.23895728602419], - [34.38105905128238, 45.24754329001464], - [34.364128286877616, 45.25499074011357], - [34.34624149762827, 45.26122745004272], - [34.327571804168144, 45.26619294328286], - [34.30830007918945, 45.26983905162751], - [34.28861316397455, 45.272130392648755], - [34.26870202072193, 45.27304472093657], - [34.248759840358034, 45.27257314931062], - [34.22898012615196, 45.2707202375966] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "safe" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/1.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/1.json deleted file mode 100644 index 25033f28b..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/1.json +++ /dev/null @@ -1,888 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "ThreatTolerantIpStrategy", - "prerequisites": [ - { - "requirement": "at least 9260 meters between", - "satisfied": true, - "subject": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - }, - "target": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from POINT (-0.0000000037252903 0.0000000000873115)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.26736233944865, 45.212832001107486], - [34.25579740516746, 45.21255839036951], - [34.244326428551396, 45.211483696916154], - [34.23306035341517, 45.20961831000684], - [34.22210811766503, 45.20698026544365], - [34.21157558717508, 45.20359506911417], - [34.20156452118371, 45.19949544747085], - [34.19217157975917, 45.194721027502304], - [34.183487383378, 45.189317949469306], - [34.17559563403959, 45.18333841635551], - [34.16857230661418, 45.17684018461397], - [34.162484918304095, 45.16988600136729], - [34.157391883200646, 45.16254299373665], - [34.153341957958176, 45.15488201642783], - [34.15037378359587, 45.14697696408575], - [34.14851552739211, 45.13890405524209], - [34.147784627771046, 45.13074109491936], - [34.14818764400937, 45.12256672311945], - [34.14972021152702, 45.11445965651546], - [34.152367102480945, 45.10649793068264], - [34.15610239036614, 45.09875815015007], - [34.16088971635356, 45.0913147534311], - [34.166682654167374, 45.0842393000012], - [34.173425169431205, 45.07759978593913], - [34.18105216860053, 45.071459994636875], - [34.18949013184899, 45.065878888618094], - [34.198657823593905, 45.06091004808918], - [34.208467073732066, 45.056601161387114], - [34.218823622111806, 45.05299357198603], - [34.229628018291784, 45.050121886187725], - [34.24077656823069, 45.048013645053835], - [34.252162319213916, 45.04668906354247], - [34.263676074053144, 45.046160839197206], - [34.27520742539138, 45.04643403210431], - [34.28664580080811, 45.04750601718975], - [34.29788150934732, 45.04936650927699], - [34.308806780083216, 45.05199766067219], - [34.31931678339612, 45.055374230391905], - [34.329310625752726, 45.05946382350324], - [34.33869230897222, 45.06422719841171], - [34.347371645212995, 45.06961863931436], - [34.35526511923397, 45.075586390437], - [34.36229668987163, 45.08207314810148], - [34.36839852312876, 45.0890166061257], - [34.37351164979367, 45.096350049549834], - [34.37758654110053, 45.10400299121158], - [34.3805835966, 45.11190184526771], - [34.38247353913498, 45.11997063137987], - [34.38323771260493, 45.12813170295747], - [34.38286827905201, 45.136306492580964], - [34.38136831250716, 45.14441626752098], - [34.37875178798923, 45.15238288812422], - [34.375043465047284, 45.16012956176131], - [34.370278666266756, 45.1675815850243], - [34.36450295221384, 45.17466706692823], - [34.35777169535828, 45.181317626009054], - [34.35014955657871, 45.1874690544232], - [34.341709868905255, 45.19306194244042], - [34.332533934174606, 45.198042257078306], - [34.32271023925041, 45.20236186905445], - [34.31233359938021, 45.20597902272556], - [34.301504237105995, 45.20885874423665], - [34.290326805903796, 45.21097318371445], - [34.27890936838613, 45.21230188799866], - [34.26736233944865, 45.212832001107486] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 15950.796923186528 meters away from POINT (-0.0000000037252903 0.0000000000873115)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [31.543677298228317, 53.94963604274752], - [30.109451949386376, 53.70926634487305], - [28.742883155610553, 53.37102777917536], - [27.46389462890607, 52.940752134787544], - [26.289149201436246, 52.42558296236213], - [25.2317755655535, 51.833680466439375], - [24.301356999465547, 51.1739227661556], - [23.504133160058522, 50.455625832669995], - [22.84335144921626, 49.6882979589566], - [22.319703234680226, 48.88143770394306], - [21.93178847958037, 48.044378075054695], - [21.676565556460687, 47.18617493458924], - [21.549757332469532, 46.31553441956308], - [21.546197458388484, 45.44077240823435], - [21.660110927788, 44.569798443987956], - [21.885330130416587, 43.71011669872251], - [22.215452128337056, 42.86883722452818], - [22.643945309246273, 42.052691678009296], - [23.164214525369015, 41.268048754360905], - [23.769633829388166, 40.52092564797081], - [24.453555363945533, 39.81699291568661], - [25.2093021139904, 39.16157113597788], - [26.03015125198358, 38.55961872054667], - [26.909313778134845, 38.01571113288901], - [27.83991511569523, 37.5340125827803], - [28.814980273384933, 37.118241969710056], - [29.82742613445757, 36.77163540753071], - [30.870062381268912, 36.49690803964221], - [31.9356015349922, 36.29621801526448], - [33.016677616846714, 36.17113542046924], - [34.10587206698068, 36.122618638708744], - [35.195744843286555, 36.15100007372277], - [36.27886811579418, 36.25598244628238], - [37.34785971226055, 36.436646039778864], - [38.39541347764873, 36.691466396894334], - [39.414323981954404, 37.018341143643624], - [40.39750352228982, 37.41462391488392], - [41.337990073220546, 37.87716283824222], - [42.22894569074836, 38.40234074051216], - [43.06364581567034, 38.98611418663667], - [43.8354609045657, 39.62404863842676], - [44.53783280852223, 40.31134740266671], - [45.164249304552754, 41.04287259045077], - [45.70822116070428, 41.81315699317169], - [46.16326708929034, 42.616406561331345], - [46.52291291603217, 43.44649402465259], - [46.780712248668415, 44.296945100310985], - [46.93029680783726, 45.160919693130595], - [46.965465259566614, 46.03119149255079], - [46.88031964092552, 46.90013040448395], - [46.66945795605362, 47.75969329008944], - [46.32822976485015, 48.601429449303446], - [45.853058007334035, 49.416508060652305], - [45.2418242929135, 50.19577517514014], - [44.49430597505506, 50.929847588985695], - [43.61264150674945, 51.60924965704153], - [42.60178663134066, 52.224596522651815], - [41.46990990648969, 52.766823101310656], - [40.22866525041226, 53.227452493221286], - [38.893276033141, 53.598890766464685], - [37.48237406067705, 53.87472823120316], - [36.01756014381054, 54.05002187596711], - [34.52268957103872, 54.121531203967244], - [33.022929636113126, 54.08788160553906], - [31.543677298228317, 53.94963604274752] - ], - [ - [34.28861316397455, 45.272130392648755], - [34.30830007918945, 45.26983905162751], - [34.327571804168144, 45.26619294328286], - [34.34624149762827, 45.26122745004272], - [34.364128286877616, 45.25499074011357], - [34.38105905128238, 45.24754329001464], - [34.39687012272915, 45.23895728602419], - [34.41140888541706, 45.229315910942596], - [34.42453525867446, 45.21871252375587], - [34.436123048042454, 45.20724974085805], - [34.44606115157486, 45.19503842845324], - [34.454254610134385, 45.182196616595895], - [34.46062549238355, 45.16884834603486], - [34.465113607141376, 45.15512245959911], - [34.46767703776809, 45.141151350297626], - [34.46829249522022, 45.127069678603554], - [34.46695548835728, 45.11301307155556], - [34.46368031195521, 45.09911681634077], - [34.458499854668645, 45.085514560930214], - [34.45146523086756, 45.07233703412435], - [34.44264524184112, 45.059710797043216], - [34.432125673303425, 45.04775703766737], - [34.42000843744777, 45.03659041951562], - [34.406410568976, 45.02631799493632], - [34.39146308557885, 45.01703819280597], - [34.37530972426567, 45.008839889674235], - [34.35810556574256, 45.00180157258149], - [34.34001555972386, 44.9959906009078], - [34.32121296464013, 44.99146257370082], - [34.301877715684206, 44.98826080797966], - [34.28219473552208, 44.98641593252975], - [34.26235220229539, 44.98594560069637], - [34.24253978976057, 44.98685432465702], - [34.22294689455304, 44.98913343261177], - [34.20376086563329, 44.992761149281165], - [34.18516525096901, 44.99770279904813], - [34.16733807643089, 45.00391113003037], - [34.150450171728366, 45.0113267563275], - [34.13466355798123, 45.01987871465802], - [34.120129911208124, 45.02948513059309], - [34.10698911560803, 45.04005398861077], - [34.095367920007305, 45.05148399924439], - [34.085378710236725, 45.063665555688864], - [34.07711840948087, 45.07648177136557], - [34.07066751780025, 45.08980958913961], - [34.06608930105789, 45.1035209521393], - [34.06342913838161, 45.11748402545735], - [34.06271403605982, 45.13156445742292], - [34.06395231440043, 45.14562666863581], - [34.0671334725843, 45.15953515655316], - [34.0722282349224, 45.17315580312883], - [34.079188780190364, 45.18635717282915], - [34.087949153880565, 45.19901178829802], - [34.0984258612984, 45.21099737102113], - [34.11051863746004, 45.22219803455216], - [34.12411138774946, 45.23250541821389], - [34.13907329129383, 45.24181974967557], - [34.155260057050576, 45.25005082543541], - [34.17251532070137, 45.25711889899864], - [34.19067216865369, 45.26295546743169], - [34.20955477379388, 45.26750394798484], - [34.22898012615196, 45.2707202375966], - [34.248759840358034, 45.27257314931062], - [34.26870202072193, 45.27304472093657], - [34.28861316397455, 45.272130392648755] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from POINT (-15541.97903142497 -3588.148585496223)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.218693248367934, 45.07345742850839], - [34.207156609034314, 45.07317858385598], - [34.19571442232239, 45.072098678335216], - [34.18447735113889, 45.07022815157965], - [34.17355405050042, 45.0675850888894], - [34.163050104272344, 45.06419504429736], - [34.1530669934107, 45.06009079059198], - [34.143701106223666, 45.05531199885625], - [34.135042800665076, 45.04990485079897], - [34.12717552805298, 45.04392158783178], - [34.12017502688297, 45.03742000147535], - [34.114108594590014, 45.03046287025475], - [34.10903444421855, 45.02311734876112], - [34.105001152001904, 45.01545431500847], - [34.102047200844716, 45.007547682598556], - [34.1002006236593, 44.99947368451849], - [34.099478749444835, 44.99131013563475], - [34.09988805392992, 44.98313568111157], - [34.10142411553777, 44.975029038072364], - [34.10407167639184, 44.96706823783931], - [34.10780480706729, 44.95932987603245], - [34.112587172821854, 44.95188837768562], - [34.11837239811455, 44.9448152843467], - [34.12510452535057, 44.93817856987773], - [34.132718562978994, 44.932041991359], - [34.1411411173231, 44.92646448113585], - [34.150291101841326, 44.92149958563124], - [34.160080516903854, 44.91719495608641], - [34.170415292625854, 44.91359189589044], - [34.181196186823364, 44.91072496862194], - [34.192319729752214, 44.90862167035846], - [34.20367920695263, 44.90730216921416], - [34.215165671252784, 44.906779114451105], - [34.226668974780914, 44.90705751687676], - [34.23807881169875, 44.908134701596275], - [34.24928576229671, 44.91000033353673], - [34.2601823290844, 44.91263651550597], - [34.270663955567315, 44.91601795789691], - [34.280630018522984, 44.92011221850257], - [34.28998478477755, 44.92488001027244], - [34.298638323736945, 44.93027557422257], - [34.306507367246816, 44.93624711411307], - [34.31351610874251, 44.94273728893414], - [34.319596934105235, 44.949683758697766], - [34.324691077163955, 44.957019778523744], - [34.32874919337364, 44.964674835538204], - [34.33173184585923, 44.97257532267728], - [34.33360989873961, 44.980645243109905], - [34.3343648134337, 44.98880693866899], - [34.33398884449988, 44.99698183541149], - [34.332485132462814, 45.0050911992202], - [34.32986769203591, 45.0130568942171], - [34.326161295141894, 45.02080213668199], - [34.32140124916276, 45.02825223716482], - [34.31563307190129, 45.035335323546164], - [34.308912065798914, 45.04198303794021], - [34.30130279501616, 45.04813120054805], - [34.29287847002852, 45.053720433855304], - [34.28372024540792, 45.05869674092705], - [34.273916437434, 45.06301203198011], - [34.263561669094074, 45.066624593906724], - [34.25275595087326, 45.069499497978484], - [34.24160370649074, 45.07160894157011], - [34.2302127533942, 45.072932520402624], - [34.218693248367934, 45.07345742850839] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 12964 meters away from POINT (-15541.97903142497 -3588.148585496223)" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.22898012615196, 45.2707202375966], - [34.20955477379388, 45.26750394798484], - [34.19067216865369, 45.26295546743169], - [34.17251532070137, 45.25711889899864], - [34.155260057050576, 45.25005082543541], - [34.13907329129383, 45.24181974967557], - [34.12411138774946, 45.23250541821389], - [34.11051863746004, 45.22219803455216], - [34.0984258612984, 45.21099737102113], - [34.087949153880565, 45.19901178829802], - [34.079188780190364, 45.18635717282915], - [34.0722282349224, 45.17315580312883], - [34.0671334725843, 45.15953515655316], - [34.06395231440043, 45.14562666863581], - [34.06271403605982, 45.13156445742292], - [34.06342913838161, 45.11748402545735], - [34.06608930105789, 45.1035209521393], - [34.07066751780025, 45.08980958913961], - [34.07711840948087, 45.07648177136557], - [34.085378710236725, 45.063665555688864], - [34.0870904867032, 45.06157851859213], - [34.09122826806114, 45.06542321762192], - [34.102241916264724, 45.07380307499917], - [34.11436485174799, 45.081376336403636], - [34.127480193708166, 45.08806973801328], - [34.14146132255797, 45.09381850568349], - [34.156173111212475, 45.09856699091037], - [34.15621831564067, 45.09857793292878], - [34.15610239036614, 45.09875815015007], - [34.152367102480945, 45.10649793068264], - [34.14972021152702, 45.11445965651546], - [34.14818764400937, 45.12256672311945], - [34.147784627771046, 45.13074109491936], - [34.14851552739211, 45.13890405524209], - [34.15037378359587, 45.14697696408575], - [34.153341957958176, 45.15488201642783], - [34.157391883200646, 45.16254299373665], - [34.162484918304095, 45.16988600136729], - [34.16857230661418, 45.17684018461397], - [34.17559563403959, 45.18333841635551], - [34.183487383378, 45.189317949469306], - [34.19217157975917, 45.194721027502304], - [34.20156452118371, 45.19949544747085], - [34.21157558717508, 45.20359506911417], - [34.22210811766503, 45.20698026544365], - [34.23306035341517, 45.20961831000684], - [34.244326428551396, 45.211483696916154], - [34.25579740516746, 45.21255839036951], - [34.26736233944865, 45.212832001107486], - [34.27890936838613, 45.21230188799866], - [34.290326805903796, 45.21097318371445], - [34.301504237105995, 45.20885874423665], - [34.31233359938021, 45.20597902272556], - [34.32271023925041, 45.20236186905445], - [34.332533934174606, 45.198042257078306], - [34.341709868905255, 45.19306194244042], - [34.35014955657871, 45.1874690544232], - [34.35777169535828, 45.181317626009054], - [34.36450295221384, 45.17466706692823], - [34.370278666266756, 45.1675815850243], - [34.375043465047284, 45.16012956176131], - [34.37875178798923, 45.15238288812422], - [34.38136831250716, 45.14441626752098], - [34.38286827905201, 45.136306492580964], - [34.38323771260493, 45.12813170295747], - [34.38247353913498, 45.11997063137987], - [34.3805835966, 45.11190184526771], - [34.37758654110053, 45.10400299121158], - [34.37351164979367, 45.096350049549834], - [34.36839852312876, 45.0890166061257], - [34.36229668987163, 45.08207314810148], - [34.35526511923397, 45.075586390437], - [34.347371645212995, 45.06961863931436], - [34.34162193326194, 45.066047215653676], - [34.345753011811674, 45.06270726142404], - [34.35515925963138, 45.05339738106913], - [34.363229885564245, 45.04347826716147], - [34.369887653840365, 45.033045728213686], - [34.37506908371292, 45.02220047726584], - [34.37872503597813, 45.01104715270264], - [34.37880497576605, 45.010614228711724], - [34.39146308557885, 45.01703819280597], - [34.406410568976, 45.02631799493632], - [34.42000843744777, 45.03659041951562], - [34.432125673303425, 45.04775703766737], - [34.44264524184112, 45.059710797043216], - [34.45146523086756, 45.07233703412435], - [34.458499854668645, 45.085514560930214], - [34.46368031195521, 45.09911681634077], - [34.46695548835728, 45.11301307155556], - [34.46829249522022, 45.127069678603554], - [34.46767703776809, 45.141151350297626], - [34.465113607141376, 45.15512245959911], - [34.46062549238355, 45.16884834603486], - [34.454254610134385, 45.182196616595895], - [34.44606115157486, 45.19503842845324], - [34.436123048042454, 45.20724974085805], - [34.42453525867446, 45.21871252375587], - [34.41140888541706, 45.229315910942596], - [34.39687012272915, 45.23895728602419], - [34.38105905128238, 45.24754329001464], - [34.364128286877616, 45.25499074011357], - [34.34624149762827, 45.26122745004272], - [34.327571804168144, 45.26619294328286], - [34.30830007918945, 45.26983905162751], - [34.28861316397455, 45.272130392648755], - [34.26870202072193, 45.27304472093657], - [34.248759840358034, 45.27257314931062], - [34.22898012615196, 45.2707202375966] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "solution" }, - "geometry": { - "type": "Point", - "coordinates": [34.170054106125676, 45.080919591691305] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/2.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/2.json deleted file mode 100644 index c2e00af93..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/2.json +++ /dev/null @@ -1,884 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "name": "UnsafeIpStrategy", - "prerequisites": [ - { - "requirement": "at least 9260 meters between", - "satisfied": true, - "subject": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - }, - "target": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - } - ] - }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.26736233944865, 45.212832001107486], - [34.25579740516746, 45.21255839036951], - [34.244326428551396, 45.211483696916154], - [34.23306035341517, 45.20961831000684], - [34.22210811766503, 45.20698026544365], - [34.21157558717508, 45.20359506911417], - [34.20156452118371, 45.19949544747085], - [34.19217157975917, 45.194721027502304], - [34.183487383378, 45.189317949469306], - [34.17559563403959, 45.18333841635551], - [34.16857230661418, 45.17684018461397], - [34.162484918304095, 45.16988600136729], - [34.157391883200646, 45.16254299373665], - [34.153341957958176, 45.15488201642783], - [34.15037378359587, 45.14697696408575], - [34.14851552739211, 45.13890405524209], - [34.147784627771046, 45.13074109491936], - [34.14818764400937, 45.12256672311945], - [34.14972021152702, 45.11445965651546], - [34.152367102480945, 45.10649793068264], - [34.15610239036614, 45.09875815015007], - [34.16088971635356, 45.0913147534311], - [34.166682654167374, 45.0842393000012], - [34.173425169431205, 45.07759978593913], - [34.18105216860053, 45.071459994636875], - [34.18949013184899, 45.065878888618094], - [34.198657823593905, 45.06091004808918], - [34.208467073732066, 45.056601161387114], - [34.218823622111806, 45.05299357198603], - [34.229628018291784, 45.050121886187725], - [34.24077656823069, 45.048013645053835], - [34.252162319213916, 45.04668906354247], - [34.263676074053144, 45.046160839197206], - [34.27520742539138, 45.04643403210431], - [34.28664580080811, 45.04750601718975], - [34.29788150934732, 45.04936650927699], - [34.308806780083216, 45.05199766067219], - [34.31931678339612, 45.055374230391905], - [34.329310625752726, 45.05946382350324], - [34.33869230897222, 45.06422719841171], - [34.347371645212995, 45.06961863931436], - [34.35526511923397, 45.075586390437], - [34.36229668987163, 45.08207314810148], - [34.36839852312876, 45.0890166061257], - [34.37351164979367, 45.096350049549834], - [34.37758654110053, 45.10400299121158], - [34.3805835966, 45.11190184526771], - [34.38247353913498, 45.11997063137987], - [34.38323771260493, 45.12813170295747], - [34.38286827905201, 45.136306492580964], - [34.38136831250716, 45.14441626752098], - [34.37875178798923, 45.15238288812422], - [34.375043465047284, 45.16012956176131], - [34.370278666266756, 45.1675815850243], - [34.36450295221384, 45.17466706692823], - [34.35777169535828, 45.181317626009054], - [34.35014955657871, 45.1874690544232], - [34.341709868905255, 45.19306194244042], - [34.332533934174606, 45.198042257078306], - [34.32271023925041, 45.20236186905445], - [34.31233359938021, 45.20597902272556], - [34.301504237105995, 45.20885874423665], - [34.290326805903796, 45.21097318371445], - [34.27890936838613, 45.21230188799866], - [34.26736233944865, 45.212832001107486] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at most 15950.796923186528 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [31.543677298228317, 53.94963604274752], - [30.109451949386376, 53.70926634487305], - [28.742883155610553, 53.37102777917536], - [27.46389462890607, 52.940752134787544], - [26.289149201436246, 52.42558296236213], - [25.2317755655535, 51.833680466439375], - [24.301356999465547, 51.1739227661556], - [23.504133160058522, 50.455625832669995], - [22.84335144921626, 49.6882979589566], - [22.319703234680226, 48.88143770394306], - [21.93178847958037, 48.044378075054695], - [21.676565556460687, 47.18617493458924], - [21.549757332469532, 46.31553441956308], - [21.546197458388484, 45.44077240823435], - [21.660110927788, 44.569798443987956], - [21.885330130416587, 43.71011669872251], - [22.215452128337056, 42.86883722452818], - [22.643945309246273, 42.052691678009296], - [23.164214525369015, 41.268048754360905], - [23.769633829388166, 40.52092564797081], - [24.453555363945533, 39.81699291568661], - [25.2093021139904, 39.16157113597788], - [26.03015125198358, 38.55961872054667], - [26.909313778134845, 38.01571113288901], - [27.83991511569523, 37.5340125827803], - [28.814980273384933, 37.118241969710056], - [29.82742613445757, 36.77163540753071], - [30.870062381268912, 36.49690803964221], - [31.9356015349922, 36.29621801526448], - [33.016677616846714, 36.17113542046924], - [34.10587206698068, 36.122618638708744], - [35.195744843286555, 36.15100007372277], - [36.27886811579418, 36.25598244628238], - [37.34785971226055, 36.436646039778864], - [38.39541347764873, 36.691466396894334], - [39.414323981954404, 37.018341143643624], - [40.39750352228982, 37.41462391488392], - [41.337990073220546, 37.87716283824222], - [42.22894569074836, 38.40234074051216], - [43.06364581567034, 38.98611418663667], - [43.8354609045657, 39.62404863842676], - [44.53783280852223, 40.31134740266671], - [45.164249304552754, 41.04287259045077], - [45.70822116070428, 41.81315699317169], - [46.16326708929034, 42.616406561331345], - [46.52291291603217, 43.44649402465259], - [46.780712248668415, 44.296945100310985], - [46.93029680783726, 45.160919693130595], - [46.965465259566614, 46.03119149255079], - [46.88031964092552, 46.90013040448395], - [46.66945795605362, 47.75969329008944], - [46.32822976485015, 48.601429449303446], - [45.853058007334035, 49.416508060652305], - [45.2418242929135, 50.19577517514014], - [44.49430597505506, 50.929847588985695], - [43.61264150674945, 51.60924965704153], - [42.60178663134066, 52.224596522651815], - [41.46990990648969, 52.766823101310656], - [40.22866525041226, 53.227452493221286], - [38.893276033141, 53.598890766464685], - [37.48237406067705, 53.87472823120316], - [36.01756014381054, 54.05002187596711], - [34.52268957103872, 54.121531203967244], - [33.022929636113126, 54.08788160553906], - [31.543677298228317, 53.94963604274752] - ], - [ - [34.28861316397455, 45.272130392648755], - [34.30830007918945, 45.26983905162751], - [34.327571804168144, 45.26619294328286], - [34.34624149762827, 45.26122745004272], - [34.364128286877616, 45.25499074011357], - [34.38105905128238, 45.24754329001464], - [34.39687012272915, 45.23895728602419], - [34.41140888541706, 45.229315910942596], - [34.42453525867446, 45.21871252375587], - [34.436123048042454, 45.20724974085805], - [34.44606115157486, 45.19503842845324], - [34.454254610134385, 45.182196616595895], - [34.46062549238355, 45.16884834603486], - [34.465113607141376, 45.15512245959911], - [34.46767703776809, 45.141151350297626], - [34.46829249522022, 45.127069678603554], - [34.46695548835728, 45.11301307155556], - [34.46368031195521, 45.09911681634077], - [34.458499854668645, 45.085514560930214], - [34.45146523086756, 45.07233703412435], - [34.44264524184112, 45.059710797043216], - [34.432125673303425, 45.04775703766737], - [34.42000843744777, 45.03659041951562], - [34.406410568976, 45.02631799493632], - [34.39146308557885, 45.01703819280597], - [34.37530972426567, 45.008839889674235], - [34.35810556574256, 45.00180157258149], - [34.34001555972386, 44.9959906009078], - [34.32121296464013, 44.99146257370082], - [34.301877715684206, 44.98826080797966], - [34.28219473552208, 44.98641593252975], - [34.26235220229539, 44.98594560069637], - [34.24253978976057, 44.98685432465702], - [34.22294689455304, 44.98913343261177], - [34.20376086563329, 44.992761149281165], - [34.18516525096901, 44.99770279904813], - [34.16733807643089, 45.00391113003037], - [34.150450171728366, 45.0113267563275], - [34.13466355798123, 45.01987871465802], - [34.120129911208124, 45.02948513059309], - [34.10698911560803, 45.04005398861077], - [34.095367920007305, 45.05148399924439], - [34.085378710236725, 45.063665555688864], - [34.07711840948087, 45.07648177136557], - [34.07066751780025, 45.08980958913961], - [34.06608930105789, 45.1035209521393], - [34.06342913838161, 45.11748402545735], - [34.06271403605982, 45.13156445742292], - [34.06395231440043, 45.14562666863581], - [34.0671334725843, 45.15953515655316], - [34.0722282349224, 45.17315580312883], - [34.079188780190364, 45.18635717282915], - [34.087949153880565, 45.19901178829802], - [34.0984258612984, 45.21099737102113], - [34.11051863746004, 45.22219803455216], - [34.12411138774946, 45.23250541821389], - [34.13907329129383, 45.24181974967557], - [34.155260057050576, 45.25005082543541], - [34.17251532070137, 45.25711889899864], - [34.19067216865369, 45.26295546743169], - [34.20955477379388, 45.26750394798484], - [34.22898012615196, 45.2707202375966], - [34.248759840358034, 45.27257314931062], - [34.26870202072193, 45.27304472093657], - [34.28861316397455, 45.272130392648755] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 9260 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.218693248367934, 45.07345742850839], - [34.207156609034314, 45.07317858385598], - [34.19571442232239, 45.072098678335216], - [34.18447735113889, 45.07022815157965], - [34.17355405050042, 45.0675850888894], - [34.163050104272344, 45.06419504429736], - [34.1530669934107, 45.06009079059198], - [34.143701106223666, 45.05531199885625], - [34.135042800665076, 45.04990485079897], - [34.12717552805298, 45.04392158783178], - [34.12017502688297, 45.03742000147535], - [34.114108594590014, 45.03046287025475], - [34.10903444421855, 45.02311734876112], - [34.105001152001904, 45.01545431500847], - [34.102047200844716, 45.007547682598556], - [34.1002006236593, 44.99947368451849], - [34.099478749444835, 44.99131013563475], - [34.09988805392992, 44.98313568111157], - [34.10142411553777, 44.975029038072364], - [34.10407167639184, 44.96706823783931], - [34.10780480706729, 44.95932987603245], - [34.112587172821854, 44.95188837768562], - [34.11837239811455, 44.9448152843467], - [34.12510452535057, 44.93817856987773], - [34.132718562978994, 44.932041991359], - [34.1411411173231, 44.92646448113585], - [34.150291101841326, 44.92149958563124], - [34.160080516903854, 44.91719495608641], - [34.170415292625854, 44.91359189589044], - [34.181196186823364, 44.91072496862194], - [34.192319729752214, 44.90862167035846], - [34.20367920695263, 44.90730216921416], - [34.215165671252784, 44.906779114451105], - [34.226668974780914, 44.90705751687676], - [34.23807881169875, 44.908134701596275], - [34.24928576229671, 44.91000033353673], - [34.2601823290844, 44.91263651550597], - [34.270663955567315, 44.91601795789691], - [34.280630018522984, 44.92011221850257], - [34.28998478477755, 44.92488001027244], - [34.298638323736945, 44.93027557422257], - [34.306507367246816, 44.93624711411307], - [34.31351610874251, 44.94273728893414], - [34.319596934105235, 44.949683758697766], - [34.324691077163955, 44.957019778523744], - [34.32874919337364, 44.964674835538204], - [34.33173184585923, 44.97257532267728], - [34.33360989873961, 44.980645243109905], - [34.3343648134337, 44.98880693866899], - [34.33398884449988, 44.99698183541149], - [34.332485132462814, 45.0050911992202], - [34.32986769203591, 45.0130568942171], - [34.326161295141894, 45.02080213668199], - [34.32140124916276, 45.02825223716482], - [34.31563307190129, 45.035335323546164], - [34.308912065798914, 45.04198303794021], - [34.30130279501616, 45.04813120054805], - [34.29287847002852, 45.053720433855304], - [34.28372024540792, 45.05869674092705], - [34.273916437434, 45.06301203198011], - [34.263561669094074, 45.066624593906724], - [34.25275595087326, 45.069499497978484], - [34.24160370649074, 45.07160894157011], - [34.2302127533942, 45.072932520402624], - [34.218693248367934, 45.07345742850839] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 12964 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.22898012615196, 45.2707202375966], - [34.20955477379388, 45.26750394798484], - [34.19067216865369, 45.26295546743169], - [34.17251532070137, 45.25711889899864], - [34.155260057050576, 45.25005082543541], - [34.13907329129383, 45.24181974967557], - [34.12411138774946, 45.23250541821389], - [34.11051863746004, 45.22219803455216], - [34.0984258612984, 45.21099737102113], - [34.087949153880565, 45.19901178829802], - [34.079188780190364, 45.18635717282915], - [34.0722282349224, 45.17315580312883], - [34.0671334725843, 45.15953515655316], - [34.06395231440043, 45.14562666863581], - [34.06271403605982, 45.13156445742292], - [34.06342913838161, 45.11748402545735], - [34.06608930105789, 45.1035209521393], - [34.07066751780025, 45.08980958913961], - [34.07711840948087, 45.07648177136557], - [34.085378710236725, 45.063665555688864], - [34.0870904867032, 45.06157851859213], - [34.09122826806114, 45.06542321762192], - [34.102241916264724, 45.07380307499917], - [34.11436485174799, 45.081376336403636], - [34.127480193708166, 45.08806973801328], - [34.14146132255797, 45.09381850568349], - [34.156173111212475, 45.09856699091037], - [34.15621831564067, 45.09857793292878], - [34.15610239036614, 45.09875815015007], - [34.152367102480945, 45.10649793068264], - [34.14972021152702, 45.11445965651546], - [34.14818764400937, 45.12256672311945], - [34.147784627771046, 45.13074109491936], - [34.14851552739211, 45.13890405524209], - [34.15037378359587, 45.14697696408575], - [34.153341957958176, 45.15488201642783], - [34.157391883200646, 45.16254299373665], - [34.162484918304095, 45.16988600136729], - [34.16857230661418, 45.17684018461397], - [34.17559563403959, 45.18333841635551], - [34.183487383378, 45.189317949469306], - [34.19217157975917, 45.194721027502304], - [34.20156452118371, 45.19949544747085], - [34.21157558717508, 45.20359506911417], - [34.22210811766503, 45.20698026544365], - [34.23306035341517, 45.20961831000684], - [34.244326428551396, 45.211483696916154], - [34.25579740516746, 45.21255839036951], - [34.26736233944865, 45.212832001107486], - [34.27890936838613, 45.21230188799866], - [34.290326805903796, 45.21097318371445], - [34.301504237105995, 45.20885874423665], - [34.31233359938021, 45.20597902272556], - [34.32271023925041, 45.20236186905445], - [34.332533934174606, 45.198042257078306], - [34.341709868905255, 45.19306194244042], - [34.35014955657871, 45.1874690544232], - [34.35777169535828, 45.181317626009054], - [34.36450295221384, 45.17466706692823], - [34.370278666266756, 45.1675815850243], - [34.375043465047284, 45.16012956176131], - [34.37875178798923, 45.15238288812422], - [34.38136831250716, 45.14441626752098], - [34.38286827905201, 45.136306492580964], - [34.38323771260493, 45.12813170295747], - [34.38247353913498, 45.11997063137987], - [34.3805835966, 45.11190184526771], - [34.37758654110053, 45.10400299121158], - [34.37351164979367, 45.096350049549834], - [34.36839852312876, 45.0890166061257], - [34.36229668987163, 45.08207314810148], - [34.35526511923397, 45.075586390437], - [34.347371645212995, 45.06961863931436], - [34.34162193326194, 45.066047215653676], - [34.345753011811674, 45.06270726142404], - [34.35515925963138, 45.05339738106913], - [34.363229885564245, 45.04347826716147], - [34.369887653840365, 45.033045728213686], - [34.37506908371292, 45.02220047726584], - [34.37872503597813, 45.01104715270264], - [34.37880497576605, 45.010614228711724], - [34.39146308557885, 45.01703819280597], - [34.406410568976, 45.02631799493632], - [34.42000843744777, 45.03659041951562], - [34.432125673303425, 45.04775703766737], - [34.44264524184112, 45.059710797043216], - [34.45146523086756, 45.07233703412435], - [34.458499854668645, 45.085514560930214], - [34.46368031195521, 45.09911681634077], - [34.46695548835728, 45.11301307155556], - [34.46829249522022, 45.127069678603554], - [34.46767703776809, 45.141151350297626], - [34.465113607141376, 45.15512245959911], - [34.46062549238355, 45.16884834603486], - [34.454254610134385, 45.182196616595895], - [34.44606115157486, 45.19503842845324], - [34.436123048042454, 45.20724974085805], - [34.42453525867446, 45.21871252375587], - [34.41140888541706, 45.229315910942596], - [34.39687012272915, 45.23895728602419], - [34.38105905128238, 45.24754329001464], - [34.364128286877616, 45.25499074011357], - [34.34624149762827, 45.26122745004272], - [34.327571804168144, 45.26619294328286], - [34.30830007918945, 45.26983905162751], - [34.28861316397455, 45.272130392648755], - [34.26870202072193, 45.27304472093657], - [34.248759840358034, 45.27257314931062], - [34.22898012615196, 45.2707202375966] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "solution" }, - "geometry": { - "type": "Point", - "coordinates": [34.170054106125676, 45.080919591691305] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/3.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/3.json deleted file mode 100644 index fd4589bea..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/3.json +++ /dev/null @@ -1,1192 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { "name": "SafeBackTrackingIpStrategy", "prerequisites": [] }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.26736233944865, 45.212832001107486], - [34.25579740516746, 45.21255839036951], - [34.244326428551396, 45.211483696916154], - [34.23306035341517, 45.20961831000684], - [34.22210811766503, 45.20698026544365], - [34.21157558717508, 45.20359506911417], - [34.20156452118371, 45.19949544747085], - [34.19217157975917, 45.194721027502304], - [34.183487383378, 45.189317949469306], - [34.17559563403959, 45.18333841635551], - [34.16857230661418, 45.17684018461397], - [34.162484918304095, 45.16988600136729], - [34.157391883200646, 45.16254299373665], - [34.153341957958176, 45.15488201642783], - [34.15037378359587, 45.14697696408575], - [34.14851552739211, 45.13890405524209], - [34.147784627771046, 45.13074109491936], - [34.14818764400937, 45.12256672311945], - [34.14972021152702, 45.11445965651546], - [34.152367102480945, 45.10649793068264], - [34.15610239036614, 45.09875815015007], - [34.16088971635356, 45.0913147534311], - [34.166682654167374, 45.0842393000012], - [34.173425169431205, 45.07759978593913], - [34.18105216860053, 45.071459994636875], - [34.18949013184899, 45.065878888618094], - [34.198657823593905, 45.06091004808918], - [34.208467073732066, 45.056601161387114], - [34.218823622111806, 45.05299357198603], - [34.229628018291784, 45.050121886187725], - [34.24077656823069, 45.048013645053835], - [34.252162319213916, 45.04668906354247], - [34.263676074053144, 45.046160839197206], - [34.27520742539138, 45.04643403210431], - [34.28664580080811, 45.04750601718975], - [34.29788150934732, 45.04936650927699], - [34.308806780083216, 45.05199766067219], - [34.31931678339612, 45.055374230391905], - [34.329310625752726, 45.05946382350324], - [34.33869230897222, 45.06422719841171], - [34.347371645212995, 45.06961863931436], - [34.35526511923397, 45.075586390437], - [34.36229668987163, 45.08207314810148], - [34.36839852312876, 45.0890166061257], - [34.37351164979367, 45.096350049549834], - [34.37758654110053, 45.10400299121158], - [34.3805835966, 45.11190184526771], - [34.38247353913498, 45.11997063137987], - [34.38323771260493, 45.12813170295747], - [34.38286827905201, 45.136306492580964], - [34.38136831250716, 45.14441626752098], - [34.37875178798923, 45.15238288812422], - [34.375043465047284, 45.16012956176131], - [34.370278666266756, 45.1675815850243], - [34.36450295221384, 45.17466706692823], - [34.35777169535828, 45.181317626009054], - [34.35014955657871, 45.1874690544232], - [34.341709868905255, 45.19306194244042], - [34.332533934174606, 45.198042257078306], - [34.32271023925041, 45.20236186905445], - [34.31233359938021, 45.20597902272556], - [34.301504237105995, 45.20885874423665], - [34.290326805903796, 45.21097318371445], - [34.27890936838613, 45.21230188799866], - [34.26736233944865, 45.212832001107486] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 9260 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.218693248367934, 45.07345742850839], - [34.207156609034314, 45.07317858385598], - [34.19571442232239, 45.072098678335216], - [34.18447735113889, 45.07022815157965], - [34.17355405050042, 45.0675850888894], - [34.163050104272344, 45.06419504429736], - [34.1530669934107, 45.06009079059198], - [34.143701106223666, 45.05531199885625], - [34.135042800665076, 45.04990485079897], - [34.12717552805298, 45.04392158783178], - [34.12017502688297, 45.03742000147535], - [34.114108594590014, 45.03046287025475], - [34.10903444421855, 45.02311734876112], - [34.105001152001904, 45.01545431500847], - [34.102047200844716, 45.007547682598556], - [34.1002006236593, 44.99947368451849], - [34.099478749444835, 44.99131013563475], - [34.09988805392992, 44.98313568111157], - [34.10142411553777, 44.975029038072364], - [34.10407167639184, 44.96706823783931], - [34.10780480706729, 44.95932987603245], - [34.112587172821854, 44.95188837768562], - [34.11837239811455, 44.9448152843467], - [34.12510452535057, 44.93817856987773], - [34.132718562978994, 44.932041991359], - [34.1411411173231, 44.92646448113585], - [34.150291101841326, 44.92149958563124], - [34.160080516903854, 44.91719495608641], - [34.170415292625854, 44.91359189589044], - [34.181196186823364, 44.91072496862194], - [34.192319729752214, 44.90862167035846], - [34.20367920695263, 44.90730216921416], - [34.215165671252784, 44.906779114451105], - [34.226668974780914, 44.90705751687676], - [34.23807881169875, 44.908134701596275], - [34.24928576229671, 44.91000033353673], - [34.2601823290844, 44.91263651550597], - [34.270663955567315, 44.91601795789691], - [34.280630018522984, 44.92011221850257], - [34.28998478477755, 44.92488001027244], - [34.298638323736945, 44.93027557422257], - [34.306507367246816, 44.93624711411307], - [34.31351610874251, 44.94273728893414], - [34.319596934105235, 44.949683758697766], - [34.324691077163955, 44.957019778523744], - [34.32874919337364, 44.964674835538204], - [34.33173184585923, 44.97257532267728], - [34.33360989873961, 44.980645243109905], - [34.3343648134337, 44.98880693866899], - [34.33398884449988, 44.99698183541149], - [34.332485132462814, 45.0050911992202], - [34.32986769203591, 45.0130568942171], - [34.326161295141894, 45.02080213668199], - [34.32140124916276, 45.02825223716482], - [34.31563307190129, 45.035335323546164], - [34.308912065798914, 45.04198303794021], - [34.30130279501616, 45.04813120054805], - [34.29287847002852, 45.053720433855304], - [34.28372024540792, 45.05869674092705], - [34.273916437434, 45.06301203198011], - [34.263561669094074, 45.066624593906724], - [34.25275595087326, 45.069499497978484], - [34.24160370649074, 45.07160894157011], - [34.2302127533942, 45.072932520402624], - [34.218693248367934, 45.07345742850839] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 12964 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [30.109451949386376, 53.70926634487305], - [28.742883155610553, 53.37102777917536], - [27.46389462890607, 52.940752134787544], - [26.289149201436246, 52.42558296236213], - [25.2317755655535, 51.833680466439375], - [24.301356999465547, 51.1739227661556], - [23.504133160058522, 50.455625832669995], - [22.84335144921626, 49.6882979589566], - [22.319703234680226, 48.88143770394306], - [21.93178847958037, 48.044378075054695], - [21.676565556460687, 47.18617493458924], - [21.549757332469532, 46.31553441956308], - [21.546197458388484, 45.44077240823435], - [21.660110927788, 44.569798443987956], - [21.885330130416587, 43.71011669872251], - [22.215452128337056, 42.86883722452818], - [22.643945309246273, 42.052691678009296], - [23.164214525369015, 41.268048754360905], - [23.769633829388166, 40.52092564797081], - [24.453555363945533, 39.81699291568661], - [25.2093021139904, 39.16157113597788], - [26.03015125198358, 38.55961872054667], - [26.909313778134845, 38.01571113288901], - [27.83991511569523, 37.5340125827803], - [28.814980273384933, 37.118241969710056], - [29.82742613445757, 36.77163540753071], - [30.870062381268912, 36.49690803964221], - [31.9356015349922, 36.29621801526448], - [33.016677616846714, 36.17113542046924], - [34.10587206698068, 36.122618638708744], - [35.195744843286555, 36.15100007372277], - [36.27886811579418, 36.25598244628238], - [37.34785971226055, 36.436646039778864], - [38.39541347764873, 36.691466396894334], - [39.414323981954404, 37.018341143643624], - [40.39750352228982, 37.41462391488392], - [41.337990073220546, 37.87716283824222], - [42.22894569074836, 38.40234074051216], - [43.06364581567034, 38.98611418663667], - [43.8354609045657, 39.62404863842676], - [44.53783280852223, 40.31134740266671], - [45.164249304552754, 41.04287259045077], - [45.70822116070428, 41.81315699317169], - [46.16326708929034, 42.616406561331345], - [46.52291291603217, 43.44649402465259], - [46.780712248668415, 44.296945100310985], - [46.93029680783726, 45.160919693130595], - [46.965465259566614, 46.03119149255079], - [46.88031964092552, 46.90013040448395], - [46.66945795605362, 47.75969329008944], - [46.32822976485015, 48.601429449303446], - [45.853058007334035, 49.416508060652305], - [45.2418242929135, 50.19577517514014], - [44.49430597505506, 50.929847588985695], - [43.61264150674945, 51.60924965704153], - [42.60178663134066, 52.224596522651815], - [41.46990990648969, 52.766823101310656], - [40.22866525041226, 53.227452493221286], - [38.893276033141, 53.598890766464685], - [37.48237406067705, 53.87472823120316], - [36.01756014381054, 54.05002187596711], - [34.52268957103872, 54.121531203967244], - [33.022929636113126, 54.08788160553906], - [31.543677298228317, 53.94963604274752], - [30.109451949386376, 53.70926634487305] - ], - [ - [34.301504237105995, 45.20885874423665], - [34.31233359938021, 45.20597902272556], - [34.32271023925041, 45.20236186905445], - [34.332533934174606, 45.198042257078306], - [34.341709868905255, 45.19306194244042], - [34.35014955657871, 45.1874690544232], - [34.35777169535828, 45.181317626009054], - [34.36450295221384, 45.17466706692823], - [34.370278666266756, 45.1675815850243], - [34.375043465047284, 45.16012956176131], - [34.37875178798923, 45.15238288812422], - [34.38136831250716, 45.14441626752098], - [34.38286827905201, 45.136306492580964], - [34.38323771260493, 45.12813170295747], - [34.38247353913498, 45.11997063137987], - [34.3805835966, 45.11190184526771], - [34.37758654110053, 45.10400299121158], - [34.37351164979367, 45.096350049549834], - [34.36839852312876, 45.0890166061257], - [34.36229668987163, 45.08207314810148], - [34.35526511923397, 45.075586390437], - [34.347371645212995, 45.06961863931436], - [34.34162193326194, 45.066047215653676], - [34.345753011811674, 45.06270726142404], - [34.35515925963138, 45.05339738106913], - [34.363229885564245, 45.04347826716147], - [34.369887653840365, 45.033045728213686], - [34.37506908371292, 45.02220047726584], - [34.37872503597813, 45.01104715270264], - [34.38082115667612, 44.99969330319595], - [34.381338174860595, 44.98824834682347], - [34.38027205285986, 44.976822514576526], - [34.37763398895121, 44.965525788526165], - [34.373450273816665, 44.95446684487245], - [34.36776200352744, 44.94375201195898], - [34.36062465310575, 44.93348425310032], - [34.35210751592655, 44.92376218374808], - [34.342293015342506, 44.91467913211939], - [34.33127589594008, 44.90632225193453], - [34.319162302759366, 44.898771695366435], - [34.30606875763754, 44.89209985369905], - [34.29212104256561, 44.88637067253156], - [34.27745300058314, 44.88163904765705], - [34.26220526528021, 44.877950306994094], - [34.24652393043235, 44.87533978316386], - [34.230559171667004, 44.873832480489355], - [34.21446383235279, 44.87344283935328], - [34.19839198611828, 44.874174599992514], - [34.182497488546936, 44.87602076693468], - [34.16693253066252, 44.878963674403415], - [34.15184620681271, 44.882975152135096], - [34.13738310948031, 44.88801679017143], - [34.12368196339763, 44.89404030031965], - [34.11087431110989, 44.900987971114546], - [34.09908326182394, 44.908793212277274], - [34.08842231498627, 44.91738118385245], - [34.078994269555366, 44.926669504421746], - [34.070890229363435, 44.93656903204677], - [34.064188714299014, 44.94698471089226], - [34.05895488628006, 44.95781647582813], - [34.05523989812661, 44.96896020671582], - [34.05308037247996, 44.980308723551836], - [34.05249801685422, 44.991752813183055], - [34.05349937974675, 45.003182277924914], - [34.05607575148255, 45.01448699611557], - [34.060203212131256, 45.02555798443043], - [34.065842827422614, 45.03628845166881], - [34.072940992112045, 45.046574833712064], - [34.081429918725505, 45.056317799443775], - [34.09122826806114, 45.06542321762192], - [34.102241916264724, 45.07380307499917], - [34.11436485174799, 45.081376336403636], - [34.127480193708166, 45.08806973801328], - [34.14146132255797, 45.09381850568349], - [34.156173111212475, 45.09856699091037], - [34.15621831564067, 45.09857793292878], - [34.15610239036614, 45.09875815015007], - [34.152367102480945, 45.10649793068264], - [34.14972021152702, 45.11445965651546], - [34.14818764400937, 45.12256672311945], - [34.147784627771046, 45.13074109491936], - [34.14851552739211, 45.13890405524209], - [34.15037378359587, 45.14697696408575], - [34.153341957958176, 45.15488201642783], - [34.157391883200646, 45.16254299373665], - [34.162484918304095, 45.16988600136729], - [34.16857230661418, 45.17684018461397], - [34.17559563403959, 45.18333841635551], - [34.183487383378, 45.189317949469306], - [34.19217157975917, 45.194721027502304], - [34.20156452118371, 45.19949544747085], - [34.21157558717508, 45.20359506911417], - [34.22210811766503, 45.20698026544365], - [34.23306035341517, 45.20961831000684], - [34.244326428551396, 45.211483696916154], - [34.25579740516746, 45.21255839036951], - [34.26736233944865, 45.212832001107486], - [34.27890936838613, 45.21230188799866], - [34.290326805903796, 45.21097318371445], - [34.301504237105995, 45.20885874423665] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "safe" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/4.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/4.json deleted file mode 100644 index ae8e60d53..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/4.json +++ /dev/null @@ -1,781 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { "name": "UnsafeBackTrackingIpStrategy", "prerequisites": [] }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - }, - { - "type": "Feature", - "properties": { - "description": "at least 9260 meters away from departure" - }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.26736233944865, 45.212832001107486], - [34.25579740516746, 45.21255839036951], - [34.244326428551396, 45.211483696916154], - [34.23306035341517, 45.20961831000684], - [34.22210811766503, 45.20698026544365], - [34.21157558717508, 45.20359506911417], - [34.20156452118371, 45.19949544747085], - [34.19217157975917, 45.194721027502304], - [34.183487383378, 45.189317949469306], - [34.17559563403959, 45.18333841635551], - [34.16857230661418, 45.17684018461397], - [34.162484918304095, 45.16988600136729], - [34.157391883200646, 45.16254299373665], - [34.153341957958176, 45.15488201642783], - [34.15037378359587, 45.14697696408575], - [34.14851552739211, 45.13890405524209], - [34.147784627771046, 45.13074109491936], - [34.14818764400937, 45.12256672311945], - [34.14972021152702, 45.11445965651546], - [34.152367102480945, 45.10649793068264], - [34.15610239036614, 45.09875815015007], - [34.16088971635356, 45.0913147534311], - [34.166682654167374, 45.0842393000012], - [34.173425169431205, 45.07759978593913], - [34.18105216860053, 45.071459994636875], - [34.18949013184899, 45.065878888618094], - [34.198657823593905, 45.06091004808918], - [34.208467073732066, 45.056601161387114], - [34.218823622111806, 45.05299357198603], - [34.229628018291784, 45.050121886187725], - [34.24077656823069, 45.048013645053835], - [34.252162319213916, 45.04668906354247], - [34.263676074053144, 45.046160839197206], - [34.27520742539138, 45.04643403210431], - [34.28664580080811, 45.04750601718975], - [34.29788150934732, 45.04936650927699], - [34.308806780083216, 45.05199766067219], - [34.31931678339612, 45.055374230391905], - [34.329310625752726, 45.05946382350324], - [34.33869230897222, 45.06422719841171], - [34.347371645212995, 45.06961863931436], - [34.35526511923397, 45.075586390437], - [34.36229668987163, 45.08207314810148], - [34.36839852312876, 45.0890166061257], - [34.37351164979367, 45.096350049549834], - [34.37758654110053, 45.10400299121158], - [34.3805835966, 45.11190184526771], - [34.38247353913498, 45.11997063137987], - [34.38323771260493, 45.12813170295747], - [34.38286827905201, 45.136306492580964], - [34.38136831250716, 45.14441626752098], - [34.37875178798923, 45.15238288812422], - [34.375043465047284, 45.16012956176131], - [34.370278666266756, 45.1675815850243], - [34.36450295221384, 45.17466706692823], - [34.35777169535828, 45.181317626009054], - [34.35014955657871, 45.1874690544232], - [34.341709868905255, 45.19306194244042], - [34.332533934174606, 45.198042257078306], - [34.32271023925041, 45.20236186905445], - [34.31233359938021, 45.20597902272556], - [34.301504237105995, 45.20885874423665], - [34.290326805903796, 45.21097318371445], - [34.27890936838613, 45.21230188799866], - [34.26736233944865, 45.212832001107486] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at least 9260 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [34.218693248367934, 45.07345742850839], - [34.207156609034314, 45.07317858385598], - [34.19571442232239, 45.072098678335216], - [34.18447735113889, 45.07022815157965], - [34.17355405050042, 45.0675850888894], - [34.163050104272344, 45.06419504429736], - [34.1530669934107, 45.06009079059198], - [34.143701106223666, 45.05531199885625], - [34.135042800665076, 45.04990485079897], - [34.12717552805298, 45.04392158783178], - [34.12017502688297, 45.03742000147535], - [34.114108594590014, 45.03046287025475], - [34.10903444421855, 45.02311734876112], - [34.105001152001904, 45.01545431500847], - [34.102047200844716, 45.007547682598556], - [34.1002006236593, 44.99947368451849], - [34.099478749444835, 44.99131013563475], - [34.09988805392992, 44.98313568111157], - [34.10142411553777, 44.975029038072364], - [34.10407167639184, 44.96706823783931], - [34.10780480706729, 44.95932987603245], - [34.112587172821854, 44.95188837768562], - [34.11837239811455, 44.9448152843467], - [34.12510452535057, 44.93817856987773], - [34.132718562978994, 44.932041991359], - [34.1411411173231, 44.92646448113585], - [34.150291101841326, 44.92149958563124], - [34.160080516903854, 44.91719495608641], - [34.170415292625854, 44.91359189589044], - [34.181196186823364, 44.91072496862194], - [34.192319729752214, 44.90862167035846], - [34.20367920695263, 44.90730216921416], - [34.215165671252784, 44.906779114451105], - [34.226668974780914, 44.90705751687676], - [34.23807881169875, 44.908134701596275], - [34.24928576229671, 44.91000033353673], - [34.2601823290844, 44.91263651550597], - [34.270663955567315, 44.91601795789691], - [34.280630018522984, 44.92011221850257], - [34.28998478477755, 44.92488001027244], - [34.298638323736945, 44.93027557422257], - [34.306507367246816, 44.93624711411307], - [34.31351610874251, 44.94273728893414], - [34.319596934105235, 44.949683758697766], - [34.324691077163955, 44.957019778523744], - [34.32874919337364, 44.964674835538204], - [34.33173184585923, 44.97257532267728], - [34.33360989873961, 44.980645243109905], - [34.3343648134337, 44.98880693866899], - [34.33398884449988, 44.99698183541149], - [34.332485132462814, 45.0050911992202], - [34.32986769203591, 45.0130568942171], - [34.326161295141894, 45.02080213668199], - [34.32140124916276, 45.02825223716482], - [34.31563307190129, 45.035335323546164], - [34.308912065798914, 45.04198303794021], - [34.30130279501616, 45.04813120054805], - [34.29287847002852, 45.053720433855304], - [34.28372024540792, 45.05869674092705], - [34.273916437434, 45.06301203198011], - [34.263561669094074, 45.066624593906724], - [34.25275595087326, 45.069499497978484], - [34.24160370649074, 45.07160894157011], - [34.2302127533942, 45.072932520402624], - [34.218693248367934, 45.07345742850839] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "at most 12964 meters away from target" }, - "geometry": { - "type": "Polygon", - "coordinates": [ - [ - [30.109451949386376, 53.70926634487305], - [28.742883155610553, 53.37102777917536], - [27.46389462890607, 52.940752134787544], - [26.289149201436246, 52.42558296236213], - [25.2317755655535, 51.833680466439375], - [24.301356999465547, 51.1739227661556], - [23.504133160058522, 50.455625832669995], - [22.84335144921626, 49.6882979589566], - [22.319703234680226, 48.88143770394306], - [21.93178847958037, 48.044378075054695], - [21.676565556460687, 47.18617493458924], - [21.549757332469532, 46.31553441956308], - [21.546197458388484, 45.44077240823435], - [21.660110927788, 44.569798443987956], - [21.885330130416587, 43.71011669872251], - [22.215452128337056, 42.86883722452818], - [22.643945309246273, 42.052691678009296], - [23.164214525369015, 41.268048754360905], - [23.769633829388166, 40.52092564797081], - [24.453555363945533, 39.81699291568661], - [25.2093021139904, 39.16157113597788], - [26.03015125198358, 38.55961872054667], - [26.909313778134845, 38.01571113288901], - [27.83991511569523, 37.5340125827803], - [28.814980273384933, 37.118241969710056], - [29.82742613445757, 36.77163540753071], - [30.870062381268912, 36.49690803964221], - [31.9356015349922, 36.29621801526448], - [33.016677616846714, 36.17113542046924], - [34.10587206698068, 36.122618638708744], - [35.195744843286555, 36.15100007372277], - [36.27886811579418, 36.25598244628238], - [37.34785971226055, 36.436646039778864], - [38.39541347764873, 36.691466396894334], - [39.414323981954404, 37.018341143643624], - [40.39750352228982, 37.41462391488392], - [41.337990073220546, 37.87716283824222], - [42.22894569074836, 38.40234074051216], - [43.06364581567034, 38.98611418663667], - [43.8354609045657, 39.62404863842676], - [44.53783280852223, 40.31134740266671], - [45.164249304552754, 41.04287259045077], - [45.70822116070428, 41.81315699317169], - [46.16326708929034, 42.616406561331345], - [46.52291291603217, 43.44649402465259], - [46.780712248668415, 44.296945100310985], - [46.93029680783726, 45.160919693130595], - [46.965465259566614, 46.03119149255079], - [46.88031964092552, 46.90013040448395], - [46.66945795605362, 47.75969329008944], - [46.32822976485015, 48.601429449303446], - [45.853058007334035, 49.416508060652305], - [45.2418242929135, 50.19577517514014], - [44.49430597505506, 50.929847588985695], - [43.61264150674945, 51.60924965704153], - [42.60178663134066, 52.224596522651815], - [41.46990990648969, 52.766823101310656], - [40.22866525041226, 53.227452493221286], - [38.893276033141, 53.598890766464685], - [37.48237406067705, 53.87472823120316], - [36.01756014381054, 54.05002187596711], - [34.52268957103872, 54.121531203967244], - [33.022929636113126, 54.08788160553906], - [31.543677298228317, 53.94963604274752], - [30.109451949386376, 53.70926634487305] - ], - [ - [34.301504237105995, 45.20885874423665], - [34.31233359938021, 45.20597902272556], - [34.32271023925041, 45.20236186905445], - [34.332533934174606, 45.198042257078306], - [34.341709868905255, 45.19306194244042], - [34.35014955657871, 45.1874690544232], - [34.35777169535828, 45.181317626009054], - [34.36450295221384, 45.17466706692823], - [34.370278666266756, 45.1675815850243], - [34.375043465047284, 45.16012956176131], - [34.37875178798923, 45.15238288812422], - [34.38136831250716, 45.14441626752098], - [34.38286827905201, 45.136306492580964], - [34.38323771260493, 45.12813170295747], - [34.38247353913498, 45.11997063137987], - [34.3805835966, 45.11190184526771], - [34.37758654110053, 45.10400299121158], - [34.37351164979367, 45.096350049549834], - [34.36839852312876, 45.0890166061257], - [34.36229668987163, 45.08207314810148], - [34.35526511923397, 45.075586390437], - [34.347371645212995, 45.06961863931436], - [34.34162193326194, 45.066047215653676], - [34.345753011811674, 45.06270726142404], - [34.35515925963138, 45.05339738106913], - [34.363229885564245, 45.04347826716147], - [34.369887653840365, 45.033045728213686], - [34.37506908371292, 45.02220047726584], - [34.37872503597813, 45.01104715270264], - [34.38082115667612, 44.99969330319595], - [34.381338174860595, 44.98824834682347], - [34.38027205285986, 44.976822514576526], - [34.37763398895121, 44.965525788526165], - [34.373450273816665, 44.95446684487245], - [34.36776200352744, 44.94375201195898], - [34.36062465310575, 44.93348425310032], - [34.35210751592655, 44.92376218374808], - [34.342293015342506, 44.91467913211939], - [34.33127589594008, 44.90632225193453], - [34.319162302759366, 44.898771695366435], - [34.30606875763754, 44.89209985369905], - [34.29212104256561, 44.88637067253156], - [34.27745300058314, 44.88163904765705], - [34.26220526528021, 44.877950306994094], - [34.24652393043235, 44.87533978316386], - [34.230559171667004, 44.873832480489355], - [34.21446383235279, 44.87344283935328], - [34.19839198611828, 44.874174599992514], - [34.182497488546936, 44.87602076693468], - [34.16693253066252, 44.878963674403415], - [34.15184620681271, 44.882975152135096], - [34.13738310948031, 44.88801679017143], - [34.12368196339763, 44.89404030031965], - [34.11087431110989, 44.900987971114546], - [34.09908326182394, 44.908793212277274], - [34.08842231498627, 44.91738118385245], - [34.078994269555366, 44.926669504421746], - [34.070890229363435, 44.93656903204677], - [34.064188714299014, 44.94698471089226], - [34.05895488628006, 44.95781647582813], - [34.05523989812661, 44.96896020671582], - [34.05308037247996, 44.980308723551836], - [34.05249801685422, 44.991752813183055], - [34.05349937974675, 45.003182277924914], - [34.05607575148255, 45.01448699611557], - [34.060203212131256, 45.02555798443043], - [34.065842827422614, 45.03628845166881], - [34.072940992112045, 45.046574833712064], - [34.081429918725505, 45.056317799443775], - [34.09122826806114, 45.06542321762192], - [34.102241916264724, 45.07380307499917], - [34.11436485174799, 45.081376336403636], - [34.127480193708166, 45.08806973801328], - [34.14146132255797, 45.09381850568349], - [34.156173111212475, 45.09856699091037], - [34.15621831564067, 45.09857793292878], - [34.15610239036614, 45.09875815015007], - [34.152367102480945, 45.10649793068264], - [34.14972021152702, 45.11445965651546], - [34.14818764400937, 45.12256672311945], - [34.147784627771046, 45.13074109491936], - [34.14851552739211, 45.13890405524209], - [34.15037378359587, 45.14697696408575], - [34.153341957958176, 45.15488201642783], - [34.157391883200646, 45.16254299373665], - [34.162484918304095, 45.16988600136729], - [34.16857230661418, 45.17684018461397], - [34.17559563403959, 45.18333841635551], - [34.183487383378, 45.189317949469306], - [34.19217157975917, 45.194721027502304], - [34.20156452118371, 45.19949544747085], - [34.21157558717508, 45.20359506911417], - [34.22210811766503, 45.20698026544365], - [34.23306035341517, 45.20961831000684], - [34.244326428551396, 45.211483696916154], - [34.25579740516746, 45.21255839036951], - [34.26736233944865, 45.212832001107486], - [34.27890936838613, 45.21230188799866], - [34.290326805903796, 45.21097318371445], - [34.301504237105995, 45.20885874423665] - ] - ] - } - }, - { - "type": "Feature", - "properties": { "description": "solution" }, - "geometry": { - "type": "Point", - "coordinates": [34.33400127364177, 45.06184561007464] - } - } - ] -} diff --git a/tests/flightplan/testcases/ip-unsafe-backtracking-required/solver.json b/tests/flightplan/testcases/ip-unsafe-backtracking-required/solver.json deleted file mode 100644 index e146bd107..000000000 --- a/tests/flightplan/testcases/ip-unsafe-backtracking-required/solver.json +++ /dev/null @@ -1,441 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { "name": "IpSolver", "terrain": "Caucasus", "doctrine": "ww2" }, - "features": [ - { - "type": "Feature", - "properties": { "description": "departure" }, - "geometry": { - "type": "Point", - "coordinates": [34.265515188456, 45.12949706032893] - } - }, - { - "type": "Feature", - "properties": { "description": "target" }, - "geometry": { - "type": "Point", - "coordinates": [34.21692562061205, 44.990118909346656] - } - }, - { - "type": "Feature", - "properties": { "description": "threat_zones" }, - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [ - [28.453527075698766, 43.296930757654664], - [28.4431948547956, 43.25787051837649], - [28.438158513659257, 43.21825826064444], - [28.43845618708483, 43.178475709185385], - [28.444074629648604, 43.138905481595614], - [28.45494974119568, 43.09992742817188], - [28.470967563324944, 43.06191502587277], - [28.491965723145853, 43.02523185872924], - [28.51773529782571, 42.990228215290486], - [28.54802307136303, 42.9572378318177], - [28.582534153539246, 42.92657480796567], - [28.620934930032792, 42.89853071964996], - [28.66285631213762, 42.873371951711114], - [28.70789725432137, 42.85133727087287], - [28.755628507898003, 42.832635657359184], - [28.805596579294537, 42.81744441139385], - [28.857327861686603, 42.80590754865379], - [28.910332909098667, 42.79813449658716], - [28.964110822358702, 42.79419910133165], - [29.018153716520647, 42.794138952777566], - [29.071951239490733, 42.79795503310811], - [29.11097408380641, 42.80359036923052], - [29.097685226995686, 42.7995696998879], - [28.796743533960743, 42.68129718349262], - [28.514256456125025, 42.54117967285618], - [28.253070075857362, 42.38072013307044], - [28.0157391641541, 42.20162165102443], - [27.804503006130737, 42.00576384368672], - [27.62126830129917, 41.79517794902235], - [27.467598848710644, 41.572021172241854], - [27.344711494218256, 41.33855080513494], - [27.253477646617362, 41.097098564366675], - [27.19442956365717, 40.85004551298279], - [27.167770564577133, 40.59979784488779], - [27.17338833526727, 40.34876373079336], - [27.210870544963736, 40.09933135096145], - [27.279522077869174, 39.85384817848173], - [27.378383287533374, 39.6146015288887], - [27.506248795510146, 39.3838003583869], - [27.661686469598827, 39.16355827338207], - [27.843056323702086, 38.95587770705681], - [28.048529175834034, 38.762635222322125], - [28.276104979882437, 38.585567912114875], - [28.523630808881336, 38.42626088496758], - [28.788818512758986, 38.28613584331228], - [29.06926210292231, 38.16644078152741], - [29.362454931616465, 38.0682408480612], - [29.66580673833051, 37.99241042927846], - [29.976660631495267, 37.939626520739466], - [29.98980788200143, 37.938425162808024], - [30.041053138973535, 37.87535499016385], - [30.18767847618667, 37.72821114612604], - [30.351178234379663, 37.59293696639063], - [30.52998333345887, 37.47076970402111], - [30.722408742234553, 37.36282293996741], - [30.92666780789326, 37.270077908899815], - [31.140886693099056, 37.193375877698884], - [31.363118899909466, 37.1334116134515], - [31.591359866904934, 37.09072797767077], - [31.82356162962148, 37.06571168138831], - [32.05764753559255, 37.058590231642214], - [32.29152700502566, 37.06943009383446], - [32.523110327179644, 37.09813608680135], - [32.750323481454124, 37.14445201874347], - [32.97112297135756, 37.20796256302053], - [33.18351065888265, 37.288096363888606], - [33.3855485860801, 37.384130354168725], - [33.575373769197526, 37.49519526010815], - [33.75121294782693, 37.620282263680494], - [33.9113972661127, 37.758250789413395], - [34.054376854185655, 37.90783738142549], - [34.17873526462974, 38.06766563634136], - [34.28320370015078, 38.23625715853593], - [34.366674944195836, 38.41204350492072], - [34.42821687598983, 38.59337908627024], - [34.46708541577956, 38.77855498984106], - [34.48273670611639, 38.96581368273128], - [34.47483829258814, 39.15336454613295], - [34.44327902507823, 39.33940017663083], - [34.38817736162232, 39.52211337160996], - [34.31114373548031, 39.69687277572057], - [34.47310247312487, 39.64988840078938], - [34.798118304289815, 39.582036549703325], - [35.12966267922132, 39.53822262662029], - [35.46487287459337, 39.51881764285328], - [35.800867307135654, 39.52397913063464], - [36.134762745341725, 39.55365048872769], - [36.46369138620446, 39.60756185310098], - [36.784817835950356, 39.68523246662975], - [37.095356041177105, 39.78597450489418], - [37.39258622829279, 39.90889830146931], - [37.673871923162636, 40.052918907213396], - [37.93667713714942, 40.21676391511722], - [38.178583817473694, 40.39898248588024], - [38.313158200284676, 40.521604803975805], - [38.50532433984624, 40.51979227619885], - [38.78222163800733, 40.537397151973984], - [39.05571806214197, 40.5749532336864], - [39.3234220834489, 40.63211399657261], - [39.582983164035205, 40.70836061992147], - [39.832106867239965, 40.8030062364142], - [40.06856993210841, 40.91520130539496], - [40.29023536688148, 41.04394006121927], - [40.49506761841093, 41.18806799088622], - [40.68114787173952, 41.34629030163202], - [40.846689524884816, 41.51718134854916], - [40.99005386638493, 41.69919500374789], - [41.109765955888264, 41.890675960912425], - [41.204530669889735, 42.08987198087033], - [41.27324882512579, 42.294947093339935], - [41.315033231431116, 42.50399577560249], - [41.3292244553117, 42.71505812873502], - [41.31540599753576, 42.926136064672704], - [41.27341850639719, 43.13521050147391], - [41.20930373749488, 43.32293985847594], - [41.31806248925841, 43.49002937873924], - [41.41764335209666, 43.69048128111702], - [41.48170699154203, 43.87249239506785], - [41.52403462503388, 43.89063138697896], - [41.70657270387867, 43.9871182472216], - [41.87575188269563, 44.09575633364793], - [42.02998756568585, 44.21556128154287], - [42.13005789328944, 44.309951764571686], - [42.302368910832385, 44.233263116329], - [42.505041332965384, 44.16128328767527], - [42.716051668576135, 44.103592114724215], - [42.93348859449922, 44.06069143196277], - [43.15540119542921, 44.03294835790311], - [43.37981286049403, 44.020593281389715], - [43.604734929600795, 44.0237188832533], - [43.82818010443886, 44.04228016814488], - [44.04817564728467, 44.0760954770092], - [44.262776397699966, 44.124848447307656], - [44.470077642720376, 44.188090886073574], - [44.66822787985488, 44.26524652041809], - [44.855441513628485, 44.355615591330185], - [45.030011524823436, 44.458380259521405], - [45.19032214623297, 44.57261079649037], - [45.334861568834235, 44.69727253959078], - [45.46223468705886, 44.83123359618272], - [45.57117587067769, 44.97327328828057], - [45.66056172333895, 45.12209133471213], - [45.72942375396579, 45.276317771813744], - [45.77696084742487, 45.43452361521272], - [45.80255137605341, 45.59523226342073], - [45.805764745318, 45.75693163799903], - [45.78637211728025, 45.91808704434022], - [45.74435600753006, 46.077154721263696], - [45.679918408298434, 46.23259602656956], - [45.5934870565428, 46.38289217974978], - [45.48571944513415, 46.52655945294007], - [45.35750417205422, 46.66216466809044], - [45.209959240484366, 46.7883408238504], - [45.044426964717964, 46.903802641804326], - [44.86246520449192, 47.007361790745854], - [44.771727402377024, 47.04923717365789], - [44.77695932602079, 47.05586067743957], - [44.82726414811353, 47.13772219457684], - [44.86573239662976, 47.22253136562483], - [44.89194554670525, 47.309488559663095], - [44.90559514443916, 47.397770257973555], - [44.90648779856951, 47.48653639938983], - [44.89454933935665, 47.57493802081855], - [44.86982802458332, 47.662125141628856], - [44.83249666967358, 47.74725483268634], - [44.782853580258504, 47.82949940235843], - [44.72132217183494, 47.90805462315147], - [44.64844917307538, 47.98214791414993], - [44.606804979018754, 48.01651833001537], - [44.815333778759545, 48.129869458189816], - [45.02631316145422, 48.26844435174603], - [45.21713170517675, 48.419749398475304], - [45.38594394526332, 48.582441203691836], - [45.53105246691135, 48.75506744943877], - [45.65092487966604, 48.936076695756356], - [45.74421143788225, 49.1238290698758], - [45.80976320645589, 49.316607896609604], - [45.846650589042994, 49.512632326888934], - [45.85418194175654, 49.71007101827466], - [45.831921891900734, 49.907056909869816], - [45.779708873246264, 50.10170311321254], - [45.697671282998044, 50.29211990971463], - [45.586241568978636, 50.476432803946906], - [45.44616747810012, 50.65280153124214], - [45.278519649274045, 50.81943985927841], - [45.08469472593388, 50.97463595908088], - [44.86641320469182, 51.11677305475539], - [44.62571133434527, 51.24434999760576], - [44.36492653675825, 51.35600135404665], - [44.08667603635859, 51.45051655310053], - [43.793828650523096, 51.52685761320711], - [43.489469995271726, 51.58417496374026], - [43.176861680190186, 51.6218208968521], - [42.859395379960915, 51.63936023107672], - [42.54054295204609, 51.63657783846044], - [42.22380399659499, 51.61348277857194], - [41.91265240509331, 51.57030889033461], - [41.61048350470695, 51.507511809400626], - [41.32056337015219, 51.425762497058074], - [41.04598174783829, 51.32593747863878], - [40.78960983018879, 51.20910608798975], - [40.55406385062741, 51.07651509409813], - [40.34167516532718, 50.92957114263795], - [40.15446717159142, 50.76982147739367], - [39.99413910843615, 50.59893341468036], - [39.86205651262352, 50.418673030342724], - [39.759247877775664, 50.23088348739089], - [39.68640689395122, 50.037463387407115], - [39.64389953293332, 49.84034547543295], - [39.631775188045374, 49.64147597085269], - [39.6497810702153, 49.442794739985786], - [39.69737909532067, 49.24621647303621], - [39.77376456141896, 49.053612981109744], - [39.877885998096346, 48.86679668962529], - [40.008465664486195, 48.68750537314997], - [40.16402026956615, 48.51738815326113], - [40.342881581918164, 48.35799276469098], - [40.54321668180716, 48.21075408455586], - [40.76304768347388, 48.076983913526576], - [41.00027081869956, 47.95786199492097], - [41.25267482393669, 47.85442825655451], - [41.517958613460834, 47.76757625962011], - [41.79374825154005, 47.69804783801282], - [42.07761325932742, 47.6464289097943], - [42.26245844916316, 47.62526461659998], - [42.24509197814767, 47.556334233994505], - [42.23585057650974, 47.467438206242406], - [42.239535027111835, 47.37835714694406], - [42.25604386491614, 47.28995211352854], - [42.285153445204095, 47.20307323493906], - [42.31998939775689, 47.131915513633864], - [42.17475973360306, 47.07521526098934], - [41.98108684685747, 46.980687771817244], - [41.80260062592443, 46.873293283085296], - [41.64106513101724, 46.75413975069337], - [41.543235060234025, 46.6655279713451], - [41.35322020124805, 46.7455759151404], - [41.138775395025405, 46.81652493695695], - [40.914696750967096, 46.87229094423107], - [40.683297091775046, 46.912277073764955], - [40.446989397342314, 46.93605008135583], - [40.20825560796418, 46.94334666261313], - [39.96961368461267, 46.934077503035624], - [39.733583697900066, 46.90832894107206], - [39.50265376544767, 46.86636219010509], - [39.27924666570969, 46.80861013030074], - [39.24488039659985, 46.79691433665712], - [39.11411690643627, 46.8751355542115], - [38.8682527510651, 46.99447443348551], - [38.60543059670348, 47.09619081657741], - [38.328339261262165, 47.17919084851914], - [38.0398690661565, 47.2425734879036], - [37.74307480749365, 47.28564392428149], - [37.64608650885292, 47.29288929387021], - [37.7231737579332, 47.35533298167254], - [37.82975522759813, 47.46077558043826], - [37.92100995746973, 47.57270808405794], - [37.99599638989834, 47.690092677459134], - [38.053907531490495, 47.81183481323839], - [38.067287281890245, 47.85352884333952], - [38.114454891478886, 47.862576276864516], - [38.28901515890454, 47.90870740552724], - [38.456353095488744, 47.96586183557921], - [38.614941862021254, 48.033521043097295], - [38.76331873061292, 48.11107050126201], - [38.90009665342268, 48.19780435662138], - [39.02397581363803, 48.29293082234487], - [39.13375512980042, 48.395578276465976], - [39.22834366637914, 48.50480205286122], - [39.3067718818553, 48.619591911793826], - [39.36820262070691, 48.738880174874446], - [39.41194172809365, 48.86155050584744], - [39.437448136564555, 48.98644731331362], - [39.44434324395583, 49.11238574401627], - [39.43241937239214, 49.238162225415735], - [39.401647071884526, 49.362565503861575], - [39.352181010665575, 49.48438810982525], - [39.284364180535526, 49.60243816467214], - [39.19873014156957, 49.71555142484701], - [39.09600303885464, 49.82260343987751], - [38.97709514638842, 49.92252168123727], - [38.843101731148735, 50.01429748100247], - [38.69529308400863, 50.09699760366252], - [38.53510363292577, 50.16977526270971], - [38.36411813574772, 50.23188038698986], - [38.18405504187618, 50.28266894131506], - [37.99674720959874, 50.32161111231795], - [37.80412026389202, 50.348298184376254], - [37.608168972138394, 50.36244795161466], - [37.410932096611276, 50.363908539973345], - [37.214466247339416, 50.3526605471055], - [37.020819302576825, 50.32881744599257], - [36.83200398349507, 50.29262423888175], - [36.64997216350322, 50.24445438948864], - [36.47659046125847, 50.184805101369165], - [36.31361761223209, 50.114291047060306], - [36.162684040473884, 50.03363668439196], - [36.02527396498187, 49.94366732204063], - [35.902710279524335, 49.845299115131404], - [35.79614234673041, 49.7395281831941], - [35.70653675227894, 49.62741904719962], - [35.63467097783759, 49.51009258031348], - [35.581129875750506, 49.38871365930556], - [35.57746123434139, 49.375658316024136], - [35.486363844992255, 49.35659626840976], - [35.30675674184261, 49.30557077275478], - [35.136078471925984, 49.24301955534111], - [34.976053272689825, 49.16958660123175], - [34.82827479987918, 49.08602526889021], - [34.69418894960209, 48.993189049817005], - [34.57507944021614, 48.892021291966245], - [34.472056272970896, 48.783544081207566], - [34.38604709881512, 48.668846477919686], - [34.31779143571198, 48.549072302289986], - [34.26783760958762, 48.4254076530029], - [34.23654223486246, 48.29906833089145], - [34.22407200838406, 48.171287323038605], - [34.230407563408136, 48.04330248498446], - [34.255349117065485, 47.91634454025151], - [34.29852364383523, 47.79162549830877], - [34.35939331680803, 47.67032757512216], - [34.437264975651495, 47.55359268512057], - [34.53130040286416, 47.442512560063925], - [34.64052721595829, 47.33811953904935], - [34.76385021074785, 47.241378064681975], - [34.78173287472014, 47.22982424027551], - [34.65408203159796, 47.21006325887035], - [34.23098480720163, 47.112780918896796], - [33.825708971742976, 46.986193203960674], - [33.527498455997865, 46.86612367941257], - [33.33099946740215, 46.93073076760182], - [32.99684821138587, 47.01311019613473], - [32.65168207038665, 47.07165056310505], - [32.29925952332686, 47.10570751093369], - [31.94345021582627, 47.11490659702082], - [31.58817549416377, 47.09914927766477], - [31.23734733552429, 47.05861439890453], - [30.894807601375387, 46.993755142807544], - [30.56426952042654, 46.90529153992812], - [30.377159237132513, 46.839461899963545], - [30.365827317686385, 46.866607242902326], - [30.324811120602615, 46.93751492934114], - [30.273725025827336, 47.005301863355264], - [30.213034589175596, 47.06930164987703], - [30.143305931320466, 47.128882890673246], - [30.065201114414684, 47.18345584976115], - [29.979472242331486, 47.23247876363219], - [29.88695431275486, 47.275463709759975], - [29.788556877730787, 47.311981949394145], - [29.685254598437847, 47.341668665245436], - [29.578076808665124, 47.36422702139024], - [29.468096228530534, 47.379431481520506], - [29.356416994066038, 47.38713033237546], - [29.24416218825064, 47.38724737156387], - [29.13246107386888, 47.37978273266263], - [29.022436237436164, 47.36481283503923], - [28.91519085588875, 47.34248946080626], - [28.81179629365351, 47.31303797617764], - [28.713280227308474, 47.27675472875069], - [28.62061547887176, 47.23400366542987], - [28.534709717658647, 47.18521222742206], - [28.456396165695782, 47.13086658865771], - [28.386425414099374, 47.071506311897735], - [28.325458428894343, 47.00771850256027], - [28.274060795737775, 46.940131543927954], - [28.232698225074554, 46.8694084989678], - [28.201733313399725, 46.79624026367697], - [28.18142353332694, 46.721338554900825], - [28.17192040562893, 46.6454288122336], - [28.173269790653944, 46.569243089216066], - [28.185413224630278, 46.493513003896425], - [28.208190218251318, 46.41896281321593], - [28.241341430318823, 46.34630266988459], - [28.284512627720698, 46.276222114648704], - [28.33725934415309, 46.20938385129781], - [28.399052153246974, 46.14641784654225], - [28.46928247659265, 46.08791579209294], - [28.547268853065617, 46.034425961925955], - [28.632263602373985, 45.986448493815644], - [28.72345982246313, 45.944431120734855], - [28.81999866698236, 45.90876537459936], - [28.920976855165126, 45.87978328200398], - [28.954119539457114, 45.87280769224353], - [28.84913856041787, 45.73469836732746], - [28.717836357468443, 45.510010415930275], - [28.61936693419261, 45.27729891035146], - [28.554289502103416, 45.03887687298874], - [28.545303218421996, 44.9699884092345], - [28.541237703422212, 44.96451088998594], - [28.44994073344265, 44.80491222038131], - [28.381476506305205, 44.63968582978034], - [28.336316136472682, 44.4704570177177], - [28.314692514718736, 44.298875106681905], - [28.316606384420645, 44.12659718113194], - [28.341834520977113, 43.955272366809965], - [28.361203338491208, 43.88746471850049], - [28.361425102583908, 43.864841958399914], - [28.375859993868403, 43.765770410368845], - [28.403543037328557, 43.66819065133277], - [28.444148432701418, 43.57303027843394], - [28.49723340763662, 43.481189882183216], - [28.535554618331563, 43.429558511422165], - [28.515149808131817, 43.407072658915915], - [28.489670018266683, 43.37189481394789], - [28.469065627105607, 43.33506182705155], - [28.453527075698766, 43.296930757654664] - ] - ] - ] - } - } - ] -} diff --git a/tests/flightplan/waypointactions/test_engagetargets.py b/tests/flightplan/waypointactions/test_engagetargets.py deleted file mode 100644 index d69d8e92d..000000000 --- a/tests/flightplan/waypointactions/test_engagetargets.py +++ /dev/null @@ -1,38 +0,0 @@ -from datetime import datetime, timedelta - -from dcs.task import Targets - -from game.ato.flightstate.actionstate import ActionState -from game.flightplan.waypointactions.engagetargets import EngageTargets -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.utils import meters - - -def test_engage_targets() -> None: - tasks = list( - EngageTargets( - meters(100), [Targets.All.Air.Planes, Targets.All.Air.Helicopters] - ).iter_tasks(TaskContext(datetime.now())) - ) - assert len(tasks) == 1 - task = tasks[0] - assert task.id == "EngageTargets" - assert task.params["targetTypes"] == { - 1: Targets.All.Air.Planes, - 2: Targets.All.Air.Helicopters, - } - assert task.params["value"] == "Planes;Helicopters" - assert task.params["maxDist"] == 100 - - -def test_engage_targets_update_state() -> None: - task = EngageTargets(meters(100), [Targets.All]) - state = ActionState(task) - assert not task.update_state(state, datetime.now(), timedelta()) - assert state.is_finished() - - -def test_engage_targets_description() -> None: - assert ( - EngageTargets(meters(100), [Targets.All]).describe() == "Searching for targets" - ) diff --git a/tests/flightplan/waypointactions/test_hold.py b/tests/flightplan/waypointactions/test_hold.py deleted file mode 100644 index e5f86a1b6..000000000 --- a/tests/flightplan/waypointactions/test_hold.py +++ /dev/null @@ -1,66 +0,0 @@ -from datetime import datetime, timedelta - -from game.ato.flightstate.actionstate import ActionState -from game.flightplan.waypointactions.hold import Hold -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.utils import meters, kph - - -def test_hold_tasks() -> None: - t0 = datetime(1999, 3, 28) - tasks = list( - Hold(lambda: t0 + timedelta(minutes=5), meters(8000), kph(400)).iter_tasks( - TaskContext(t0 + timedelta(minutes=1)) - ) - ) - assert len(tasks) == 1 - task = tasks[0] - assert task.id == "ControlledTask" - assert task.params["stopCondition"]["time"] == 4 * 60 - assert task.params["task"]["id"] == "Orbit" - assert task.params["task"]["params"]["altitude"] == 8000 - assert task.params["task"]["params"]["pattern"] == "Circle" - assert task.params["task"]["params"]["speed"] == kph(400).meters_per_second - - -def test_hold_task_at_or_after_push() -> None: - t0 = datetime(1999, 3, 28) - assert not list( - Hold(lambda: t0, meters(8000), kph(400)).iter_tasks(TaskContext(t0)) - ) - assert not list( - Hold(lambda: t0, meters(8000), kph(400)).iter_tasks( - TaskContext(t0 + timedelta(minutes=1)) - ) - ) - - -def test_hold_tick() -> None: - t0 = datetime(1999, 3, 28) - task = Hold(lambda: t0 + timedelta(minutes=5), meters(8000), kph(400)) - state = ActionState(task) - assert not task.update_state(state, t0, timedelta()) - assert not state.is_finished() - assert not task.update_state(state, t0 + timedelta(minutes=1), timedelta(minutes=1)) - assert not state.is_finished() - assert not task.update_state(state, t0 + timedelta(minutes=2), timedelta(minutes=1)) - assert not state.is_finished() - assert not task.update_state(state, t0 + timedelta(minutes=3), timedelta(minutes=1)) - assert not state.is_finished() - assert not task.update_state(state, t0 + timedelta(minutes=4), timedelta(minutes=1)) - assert not state.is_finished() - assert not task.update_state(state, t0 + timedelta(minutes=5), timedelta(minutes=1)) - assert state.is_finished() - assert task.update_state( - state, t0 + timedelta(minutes=6), timedelta(minutes=1) - ) == timedelta(minutes=1) - assert state.is_finished() - - -def test_hold_description() -> None: - assert ( - Hold( - lambda: datetime(1999, 3, 28) + timedelta(minutes=5), meters(8000), kph(400) - ).describe() - == "Holding until 00:05:00" - ) diff --git a/tests/flightplan/waypointoptions/__init__.py b/tests/flightplan/waypointoptions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/flightplan/waypointoptions/test_formation.py b/tests/flightplan/waypointoptions/test_formation.py deleted file mode 100644 index 7f1063090..000000000 --- a/tests/flightplan/waypointoptions/test_formation.py +++ /dev/null @@ -1,13 +0,0 @@ -from datetime import datetime - -from dcs.task import OptFormation - -from game.flightplan.waypointactions.taskcontext import TaskContext -from game.flightplan.waypointoptions.formation import Formation - - -def test_formation() -> None: - tasks = list(Formation.LINE_ABREAST_OPEN.iter_tasks(TaskContext(datetime.now()))) - assert len(tasks) == 1 - task = tasks[0] - assert task.dict() == OptFormation.line_abreast_open().dict() diff --git a/tests/flightplan/waypointsolvertestcasereducer.py b/tests/flightplan/waypointsolvertestcasereducer.py deleted file mode 100644 index ab0c5ad56..000000000 --- a/tests/flightplan/waypointsolvertestcasereducer.py +++ /dev/null @@ -1,159 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from collections.abc import Iterator -from pathlib import Path -from typing import Any, TypeVar, Generic - -from shapely import Point, MultiPolygon -from shapely.geometry import shape - -from game.data.doctrine import Doctrine -from game.flightplan.ipsolver import IpSolver -from game.flightplan.waypointsolver import WaypointSolver, NoSolutionsError -from game.flightplan.waypointsolverloader import WaypointSolverLoader -from game.theater.theaterloader import TERRAINS_BY_NAME - -ReducerT = TypeVar("ReducerT") - - -def doctrine_from_name(name: str) -> Doctrine: - return Doctrine.named(name) - - -class Reducer(Generic[ReducerT], Iterator[ReducerT], ABC): - @abstractmethod - def accept(self) -> None: - ... - - @abstractmethod - def reject(self) -> None: - ... - - -class MultiPolyReducer(Reducer[MultiPolygon]): - def __init__(self, multipoly: MultiPolygon) -> None: - self._multipoly: MultiPolygon | None = multipoly - self._previous_poly: MultiPolygon | None = None - self._remove_index = 0 - - def __next__(self) -> MultiPolygon: - if self._multipoly is None: - raise StopIteration - return self._multipoly - - def _reduce_poly(self) -> None: - assert self._multipoly is not None - polys = list(self._multipoly.geoms) - if not polys or self._remove_index >= len(polys): - self._multipoly = None - return - - del polys[self._remove_index] - self._previous_poly = self._multipoly - self._multipoly = MultiPolygon(polys) - - def accept(self) -> None: - self._reduce_poly() - - def reject(self) -> None: - self._multipoly = self._previous_poly - self._previous_poly = None - self._remove_index += 1 - self._reduce_poly() - - -class IpSolverReducer(Reducer[IpSolver]): - def __init__( - self, - departure: Point, - target: Point, - doctrine: Doctrine, - threat_zones: MultiPolygon, - ) -> None: - self.departure = departure - self.target = target - self.doctrine = doctrine - self.threat_zones_reducer = MultiPolyReducer(threat_zones) - - @staticmethod - def from_metadata_and_feature_collection( - metadata: dict[str, Any], feature_collection: dict[str, Any] - ) -> IpSolverReducer: - departure: Point | None = None - target: Point | None = None - threat_zones: MultiPolygon | None = None - for feature in feature_collection["features"]: - description = feature["properties"]["description"] - geometry = feature["geometry"] - match description: - case "departure": - departure = shape(geometry) - case "target": - target = shape(geometry) - case "threat_zones": - threat_zones = shape(geometry) - - if departure is None: - raise KeyError("feature collection has no departure point") - if target is None: - raise KeyError("feature collection has no target point") - if threat_zones is None: - raise KeyError("feature collection has no threat zones") - - return IpSolverReducer( - departure, - target, - doctrine_from_name(metadata["doctrine"]), - threat_zones, - ) - - def __next__(self) -> IpSolver: - return IpSolver( - self.departure, self.target, self.doctrine, next(self.threat_zones_reducer) - ) - - def accept(self) -> None: - self.threat_zones_reducer.accept() - - def reject(self) -> None: - self.threat_zones_reducer.reject() - - -class WaypointSolverTestCaseReducer: - def __init__(self, debug_directory: Path, out_dir: Path) -> None: - self.debug_directory = debug_directory - self.out_dir = out_dir - if self.out_dir.exists(): - raise ValueError(f"out_dir {out_dir} already exists") - - @staticmethod - def _reducer_from_solver(solver: WaypointSolver) -> Reducer[Any]: - if isinstance(solver, IpSolver): - return IpSolverReducer( - solver.departure, solver.target, solver.doctrine, solver.threat_zones - ) - else: - raise KeyError(f"Unhandled waypoint solver {solver.__class__.__name__}") - - def reduce(self) -> None: - loader = WaypointSolverLoader(self.debug_directory / "solver.json") - solver = loader.load() - last_broken: WaypointSolver | None = None - reducer = self._reducer_from_solver(solver) - for solver in reducer: - try: - solver.solve() - reducer.reject() - except NoSolutionsError: - last_broken = solver - reducer.accept() - - if last_broken is None: - raise RuntimeError("all cases succeeded, nothing to reduce") - - self.out_dir.mkdir(parents=True) - last_broken.set_debug_properties( - self.out_dir, TERRAINS_BY_NAME[loader.load_data()["metadata"]["terrain"]] - ) - last_broken.dump_debug_info() diff --git a/tests/lasercodes/__init__.py b/tests/lasercodes/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/lasercodes/test_lasercode.py b/tests/lasercodes/test_lasercode.py deleted file mode 100644 index 49d73acfa..000000000 --- a/tests/lasercodes/test_lasercode.py +++ /dev/null @@ -1,74 +0,0 @@ -import pytest - -from game.lasercodes import ILaserCodeRegistry -from game.lasercodes.lasercode import LaserCode - - -class MockRegistry(ILaserCodeRegistry): - def __init__(self) -> None: - self.release_count = 0 - - def alloc_laser_code(self) -> LaserCode: - raise NotImplementedError - - def release_code(self, code: LaserCode) -> None: - self.release_count += 1 - - -@pytest.fixture(name="registry") -def mock_registry() -> MockRegistry: - return MockRegistry() - - -def test_lasercode_code(registry: ILaserCodeRegistry) -> None: - assert LaserCode(1688, registry).code == 1688 - - # 1113 doesn't comply to the rules, but is the only code valid for FC3 aircraft like - # the A-10A. - assert LaserCode(1113, registry).code == 1113 - - # The first digit must be 1 - with pytest.raises(ValueError): - # And be exactly 4 digits - LaserCode(2688, registry) - - # The code must be exactly 4 digits - with pytest.raises(ValueError): - LaserCode(888, registry) - with pytest.raises(ValueError): - LaserCode(18888, registry) - - # 0 and 9 are invalid digits - with pytest.raises(ValueError): - LaserCode(1088, registry) - with pytest.raises(ValueError): - LaserCode(1608, registry) - with pytest.raises(ValueError): - LaserCode(1680, registry) - with pytest.raises(ValueError): - LaserCode(1988, registry) - with pytest.raises(ValueError): - LaserCode(1698, registry) - with pytest.raises(ValueError): - LaserCode(1689, registry) - - # The second digit is further constrained to be 5, 6, or 7. - with pytest.raises(ValueError): - LaserCode(1188, registry) - with pytest.raises(ValueError): - LaserCode(1288, registry) - with pytest.raises(ValueError): - LaserCode(1388, registry) - with pytest.raises(ValueError): - LaserCode(1488, registry) - with pytest.raises(ValueError): - LaserCode(1888, registry) - - -def test_lasercode_release(registry: MockRegistry) -> None: - code = LaserCode(1688, registry) - assert registry.release_count == 0 - code.release() - assert registry.release_count == 1 - code.release() - assert registry.release_count == 2 diff --git a/tests/lasercodes/test_lasercoderegistry.py b/tests/lasercodes/test_lasercoderegistry.py deleted file mode 100644 index 2f8a3a8f0..000000000 --- a/tests/lasercodes/test_lasercoderegistry.py +++ /dev/null @@ -1,25 +0,0 @@ -from game.lasercodes.lasercoderegistry import LaserCodeRegistry - - -def test_initial_laser_codes() -> None: - reg = LaserCodeRegistry() - assert list(reg.available_codes)[:5] == [1688, 1687, 1686, 1685, 1684] - assert list(reg.available_codes)[-5:] == [1715, 1714, 1713, 1712, 1711] - assert len(reg.available_codes) == 192 - - -def test_alloc_laser_code() -> None: - reg = LaserCodeRegistry() - assert reg.alloc_laser_code().code == 1688 - assert 1688 not in reg.available_codes - assert len(reg.available_codes) == 191 - - -def test_release_code() -> None: - reg = LaserCodeRegistry() - code = reg.alloc_laser_code() - code.release() - assert code.code in reg.available_codes - assert len(reg.available_codes) == 192 - code.release() - assert len(reg.available_codes) == 192 diff --git a/tests/missiongenerator/aircraft/test_bingoestimator.py b/tests/missiongenerator/aircraft/test_bingoestimator.py deleted file mode 100644 index 338f7bfdf..000000000 --- a/tests/missiongenerator/aircraft/test_bingoestimator.py +++ /dev/null @@ -1,51 +0,0 @@ -import pytest -from dcs import Point -from dcs.terrain import Terrain, Caucasus - -from game.ato import FlightWaypoint -from game.ato.flightwaypointtype import FlightWaypointType -from game.dcs.aircrafttype import FuelConsumption -from game.missiongenerator.aircraft.bingoestimator import BingoEstimator -from game.utils import nautical_miles - - -@pytest.fixture(name="terrain") -def terrain_fixture() -> Terrain: - return Caucasus() - - -@pytest.fixture(name="waypoints") -def waypoints_fixture(terrain: Terrain) -> list[FlightWaypoint]: - return [ - FlightWaypoint( - "", FlightWaypointType.NAV, Point(0, nautical_miles(d).meters, terrain) - ) - for d in range(101) - ] - - -def test_legacy_bingo_estimator( - waypoints: list[FlightWaypoint], terrain: Terrain -) -> None: - estimator = BingoEstimator(None, Point(0, 0, terrain), None, waypoints) - assert estimator.estimate_bingo() == 3000 - assert estimator.estimate_joker() == estimator.estimate_bingo() + 1000 - estimator = BingoEstimator( - None, Point(0, 0, terrain), Point(0, 5, terrain), waypoints - ) - assert estimator.estimate_bingo() == 4000 - assert estimator.estimate_joker() == estimator.estimate_bingo() + 1000 - - -def test_fuel_consumption_based_bingo_estimator( - waypoints: list[FlightWaypoint], terrain: Terrain -) -> None: - consumption = FuelConsumption(100, 50, 10, 25, 1000) - estimator = BingoEstimator(consumption, Point(0, 0, terrain), None, waypoints) - assert estimator.estimate_bingo() == 2000 - assert estimator.estimate_joker() == estimator.estimate_bingo() + 1000 - estimator = BingoEstimator( - consumption, Point(0, 0, terrain), Point(0, 5, terrain), waypoints - ) - assert estimator.estimate_bingo() == 2000 - assert estimator.estimate_joker() == estimator.estimate_bingo() + 1000 diff --git a/tests/persistence/__init__.py b/tests/persistence/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/persistence/conftest.py b/tests/persistence/conftest.py deleted file mode 100644 index fb5984969..000000000 --- a/tests/persistence/conftest.py +++ /dev/null @@ -1,18 +0,0 @@ -import datetime -from typing import cast - -import pytest - -from game import Game -from game.persistence import SaveManager - - -class StubGame: - def __init__(self) -> None: - self.date = datetime.date.min - self.save_manager = SaveManager(cast(Game, self)) - - -@pytest.fixture -def game() -> Game: - return cast(Game, StubGame()) diff --git a/tests/persistence/test_savegamebundle.py b/tests/persistence/test_savegamebundle.py deleted file mode 100644 index a31a8d264..000000000 --- a/tests/persistence/test_savegamebundle.py +++ /dev/null @@ -1,114 +0,0 @@ -import datetime -from pathlib import Path -from zipfile import ZipFile - -import pytest - -from game import Game -from game.persistence.savegamebundle import SaveGameBundle - - -@pytest.fixture -def tmp_bundle(tmp_zip: Path) -> SaveGameBundle: - return SaveGameBundle(tmp_zip) - - -def test_save_player_new_save(game: Game, tmp_bundle: SaveGameBundle) -> None: - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - with pytest.raises(KeyError): - zip_file.read(SaveGameBundle.MANUAL_SAVE_NAME) - tmp_bundle.save_player(game, copy_from=None) - - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - assert zip_file.namelist() == [SaveGameBundle.MANUAL_SAVE_NAME] - - -def test_save_player_existing_save(game: Game, tmp_bundle: SaveGameBundle) -> None: - game.date = datetime.date.min - tmp_bundle.save_start_of_turn(game) - tmp_bundle.save_player(game, copy_from=tmp_bundle) - - test_date = datetime.date.today() - game.date = test_date - tmp_bundle.save_player(game, copy_from=tmp_bundle) - - assert tmp_bundle.load_start_of_turn().date == datetime.date.min - assert tmp_bundle.load_player().date == test_date - - -def test_save_last_turn(game: Game, tmp_bundle: SaveGameBundle) -> None: - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - with pytest.raises(KeyError): - zip_file.read(SaveGameBundle.LAST_TURN_SAVE_NAME) - tmp_bundle.save_last_turn(game) - - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - assert zip_file.namelist() == [SaveGameBundle.LAST_TURN_SAVE_NAME] - - -def test_save_start_of_turn(game: Game, tmp_bundle: SaveGameBundle) -> None: - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - with pytest.raises(KeyError): - zip_file.read(SaveGameBundle.START_OF_TURN_SAVE_NAME) - tmp_bundle.save_start_of_turn(game) - - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - assert zip_file.namelist() == [SaveGameBundle.START_OF_TURN_SAVE_NAME] - - -def test_save_pre_sim_checkpoint(game: Game, tmp_bundle: SaveGameBundle) -> None: - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - with pytest.raises(KeyError): - zip_file.read(SaveGameBundle.PRE_SIM_CHECKPOINT_SAVE_NAME) - tmp_bundle.save_pre_sim_checkpoint(game) - - with ZipFile(tmp_bundle.bundle_path, "r") as zip_file: - assert zip_file.namelist() == [SaveGameBundle.PRE_SIM_CHECKPOINT_SAVE_NAME] - - -def test_failed_save_leaves_original_intact( - game: Game, tmp_bundle: SaveGameBundle -) -> None: - expect_date = datetime.date.today() - game.date = expect_date - tmp_bundle.save_player(game, copy_from=None) - - # Add some non-pickleable member to the game to cause an error on save. - def local_f() -> None: - pass - - game.garbage = local_f # type: ignore - with pytest.raises(AttributeError): - tmp_bundle.save_player(game, copy_from=tmp_bundle) - - assert tmp_bundle.load_player().date == expect_date - - -def test_load_reads_correct_data(game: Game, tmp_bundle: SaveGameBundle) -> None: - last_turn_date = datetime.date.today() - datetime.timedelta(days=2) - game.date = last_turn_date - tmp_bundle.save_last_turn(game) - - start_of_turn_date = datetime.date.today() - datetime.timedelta(days=1) - game.date = start_of_turn_date - tmp_bundle.save_start_of_turn(game) - - player_date = datetime.date.today() - game.date = player_date - tmp_bundle.save_player(game, copy_from=tmp_bundle) - - assert tmp_bundle.load_last_turn().date == last_turn_date - assert tmp_bundle.load_start_of_turn().date == start_of_turn_date - assert tmp_bundle.load_player().date == player_date - - -def test_load_from_absent_file_raises(tmp_bundle: SaveGameBundle) -> None: - tmp_bundle.bundle_path.unlink(missing_ok=True) - with pytest.raises(FileNotFoundError): - tmp_bundle.load_last_turn() - - -def test_load_from_absent_member_raises(game: Game, tmp_bundle: SaveGameBundle) -> None: - tmp_bundle.save_start_of_turn(game) - with pytest.raises(KeyError): - tmp_bundle.load_last_turn() diff --git a/tests/persistence/test_savemanager.py b/tests/persistence/test_savemanager.py deleted file mode 100644 index 190b23702..000000000 --- a/tests/persistence/test_savemanager.py +++ /dev/null @@ -1,179 +0,0 @@ -import datetime -from pathlib import Path -from unittest.mock import Mock - -import pytest -from pytest_mock import MockerFixture - -from game import Game -from game.persistence import SaveManager, set_dcs_save_game_directory - - -@pytest.fixture(autouse=True) -def mock_setup_last_save_file(mocker: MockerFixture) -> Mock: - return mocker.patch("qt_ui.liberation_install.setup_last_save_file") - - -@pytest.fixture(autouse=True) -def mock_save_config(mocker: MockerFixture) -> Mock: - return mocker.patch("qt_ui.liberation_install.save_config") - - -@pytest.fixture(autouse=True) -def setup_persistence_paths(tmp_path: Path) -> None: - set_dcs_save_game_directory(tmp_path) - - -@pytest.fixture -def save_manager(game: Game) -> SaveManager: - return game.save_manager - - -def test_new_savemanager_saves_to_autosave(save_manager: SaveManager) -> None: - assert save_manager.default_save_location == save_manager.autosave_path - - -def test_savemanager_saves_to_last_save_location(save_manager: SaveManager) -> None: - save_manager.player_save_location = Path("Saves/foo.liberation.zip") - assert save_manager.default_save_location == save_manager.player_save_location - - -def test_saving_without_name_saves_to_autosave_path(save_manager: SaveManager) -> None: - assert not save_manager.autosave_path.exists() - save_manager.save_player() - assert save_manager.autosave_path.exists() - - -def test_saving_with_name_updates_last_save_location( - save_manager: SaveManager, tmp_path: Path -) -> None: - save_path = tmp_path / "foo.liberation.zip" - assert not save_path.exists() - save_manager.save_player(override_destination=save_path) - assert save_path.exists() - assert save_manager.last_saved_bundle is not None - assert save_manager.last_saved_bundle.bundle_path == save_path - - -def test_player_save_location(save_manager: SaveManager, tmp_path: Path) -> None: - assert save_manager.player_save_location is None - save_manager.save_last_turn() - assert save_manager.player_save_location is None - save_manager.save_start_of_turn() - assert save_manager.player_save_location is None - expect_location = tmp_path / "player.liberation.zip" - save_manager.save_player(override_destination=expect_location) - assert save_manager.player_save_location == expect_location - - -def test_saving_updates_preferences_with_save_location( - save_manager: SaveManager, mock_setup_last_save_file: Mock, mock_save_config: Mock -) -> None: - save_manager.save_player() - mock_setup_last_save_file.assert_called_once_with( - str(save_manager.default_save_location) - ) - mock_save_config.assert_called_once() - - -def test_non_player_saves_do_not_update_preferences( - save_manager: SaveManager, mock_setup_last_save_file: Mock -) -> None: - save_manager.save_last_turn() - mock_setup_last_save_file.assert_not_called() - save_manager.save_start_of_turn() - mock_setup_last_save_file.assert_not_called() - - -def test_load_game_loads_correct_data(save_manager: SaveManager) -> None: - test_date = datetime.date.today() - assert save_manager.game.date != test_date - save_manager.game.date = test_date - save_manager.save_player() - game = SaveManager.load_player_save(save_manager.default_save_location) - assert game.date == test_date - - -def test_loading_missing_save_raises() -> None: - with pytest.raises(FileNotFoundError): - SaveManager.load_player_save(Path("does not exist")) - - -def test_saving_after_autosave_copies_autosave_members( - save_manager: SaveManager, tmp_path: Path -) -> None: - save_manager.save_start_of_turn() - - save_path = tmp_path / "foo.liberation.zip" - save_manager.save_player(override_destination=save_path) - - SaveManager.load_start_of_turn(save_path) - - -def test_failed_save_does_not_update_last_saved_path( - save_manager: SaveManager, tmp_path: Path -) -> None: - expect_date = datetime.date.today() - save_manager.game.date = expect_date - save_manager.save_player() - assert save_manager.last_saved_bundle is not None - expect_path = save_manager.last_saved_bundle.bundle_path - - # Add some non-pickleable member to the game to cause an error on save. - def local_f() -> None: - pass - - save_manager.game.garbage = local_f # type: ignore - with pytest.raises(AttributeError): - save_manager.save_player( - override_destination=tmp_path / "badsave.liberation.zip" - ) - - assert save_manager.last_saved_bundle.bundle_path == expect_path - - -def test_load_reads_correct_data(save_manager: SaveManager) -> None: - last_turn_date = datetime.date.today() - datetime.timedelta(days=2) - save_manager.game.date = last_turn_date - save_manager.save_last_turn() - - start_of_turn_date = datetime.date.today() - datetime.timedelta(days=1) - save_manager.game.date = start_of_turn_date - save_manager.save_start_of_turn() - - player_date = datetime.date.today() - save_manager.game.date = player_date - save_manager.save_player() - - assert save_manager.last_saved_bundle is not None - bundle_path = save_manager.last_saved_bundle.bundle_path - assert SaveManager.load_last_turn(bundle_path).date == last_turn_date - assert SaveManager.load_start_of_turn(bundle_path).date == start_of_turn_date - assert SaveManager.load_player_save(bundle_path).date == player_date - - -def test_save_after_loading_foreign_save( - save_manager: SaveManager, tmp_path: Path -) -> None: - """Tests that we can save games that were copied from another machine. - - Regression test for https://github.com/dcs-liberation/dcs_liberation/issues/2756. - """ - # To simulate the situation from the bug, we save a game to a directory, move it out - # of that directory, delete the directory, then attempt to load and save the game. - # It should save to the new location. If it tries to save to the old location, it - # will fail because the directory does not exist. - - # Create the save on "the other machine"... - bad_directory = tmp_path / "other-machine" - bad_directory.mkdir() - bad_save_path = bad_directory / "foo.liberation.zip" - save_manager.save_player(override_destination=bad_save_path) - - good_save_path = tmp_path / "foo.liberation.zip" - bad_save_path.rename(good_save_path) - bad_directory.rmdir() - - game = SaveManager.load_player_save(good_save_path) - assert game.save_manager.player_save_location == good_save_path - game.save_manager.save_player() diff --git a/tests/resources/invalid_faction_country.json b/tests/resources/invalid_faction_country.json deleted file mode 100644 index 41255ff63..000000000 --- a/tests/resources/invalid_faction_country.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "country": "C", - "name": "USA 2005", - "authors": "Khopa", - "description": "This is a test description", - "aircrafts": [ - "F_15C", - "F_15E", - "F_14B", - "FA_18C_hornet", - "F_16C_50", - "A_10A", - "AV8BNA", - "UH_1H", - "AH_64A", - "B_52H", - "B_1B", - "F_117A" - ], - "awacs": [ - "E_3A" - ], - "tankers": [ - "KC_135", - "KC130" - ], - "frontline_units": [ - "MBT_M1A2_Abrams", - "ATGM_Stryker", - "IFV_M1126_Stryker_ICV", - "IFV_M2A2_Bradley", - "IFV_LAV_25", - "Scout_HMMWV", - "ATGM_HMMWV" - ], - "artillery_units": [ - "MLRS_M270_227mm", - "SPH_M109_Paladin_155mm" - ], - "logistics_units": [ - "M_818" - ], - "infantry_units": [ - "Infantry_M4", - "Infantry_M249" - ], - "shorads": [ - "AvengerGenerator" - ], - "sams": [ - "HawkGenerator" - ], - "aircraft_carrier": [ - "Stennis" - ], - "helicopter_carrier": [ - "LHA_Tarawa" - ], - "destroyers": [ - "PERRY", - "USS_Arleigh_Burke_IIa" - ], - "cruisers": [ - "TICONDEROG" - ], - "requirements": {"mod": "Some mod is required"}, - "carrier_names": [ - "CVN-71 Theodore Roosevelt", - "CVN-72 Abraham Lincoln", - "CVN-73 George Washington", - "CVN-74 John C. Stennis" - ], - "helicopter_carrier_names": [ - "LHA-1 Tarawa", - "LHA-2 Saipan", - "LHA-3 Belleau Wood", - "LHA-4 Nassau", - "LHA-5 Peleliu" - ], - "navy_generators": [ - "OliverHazardPerryGroupGenerator", - "ArleighBurkeGroupGenerator" - ], - "has_jtac": true, - "jtac_unit": "MQ_9_Reaper" -} diff --git a/tests/resources/valid_faction.json b/tests/resources/valid_faction.json deleted file mode 100644 index 620fa9df8..000000000 --- a/tests/resources/valid_faction.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "country": "USA", - "name": "USA 2005", - "authors": "Khopa", - "description": "This is a test description", - "aircrafts": [ - "F_15C", - "F_15E", - "F_14B", - "FA_18C_hornet", - "F_16C_50", - "A_10A", - "AV8BNA", - "UH_1H", - "AH_64A", - "B_52H", - "B_1B", - "F_117A", - "A_10C", - "A_10C_2" - ], - "awacs": [ - "E_3A" - ], - "tankers": [ - "KC_135", - "KC130" - ], - "frontline_units": [ - "MBT_M1A2_Abrams", - "ATGM_Stryker", - "IFV_M1126_Stryker_ICV", - "IFV_M2A2_Bradley", - "IFV_LAV_25", - "Scout_HMMWV", - "ATGM_HMMWV" - ], - "artillery_units": [ - "MLRS_M270_227mm", - "SPH_M109_Paladin_155mm" - ], - "logistics_units": [ - "M_818" - ], - "infantry_units": [ - "Infantry_M4", - "Infantry_M249" - ], - "shorads": [ - "AvengerGenerator" - ], - "sams": [ - "HawkGenerator" - ], - "naval_units": [ - "LHA-1 Tarawa", - "CVN-74 John C. Stennis" - ], - "requirements": {"mod": "Some mod is required"}, - "carrier_names": [ - "CVN-71 Theodore Roosevelt", - "CVN-72 Abraham Lincoln", - "CVN-73 George Washington", - "CVN-74 John C. Stennis" - ], - "helicopter_carrier_names": [ - "LHA-1 Tarawa", - "LHA-2 Saipan", - "LHA-3 Belleau Wood", - "LHA-4 Nassau", - "LHA-5 Peleliu" - ], - "has_jtac": true, - "jtac_unit": "MQ_9_Reaper" -} diff --git a/tests/test_daytimemap.py b/tests/test_daytimemap.py deleted file mode 100644 index 2082679be..000000000 --- a/tests/test_daytimemap.py +++ /dev/null @@ -1,107 +0,0 @@ -from datetime import time - -import pytest - -from game.theater.daytimemap import DaytimeMap -from game.timeofday import TimeOfDay - - -def test_range_of() -> None: - m = DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=0), time(hour=5)), - ) - - assert m.range_of(TimeOfDay.Dawn) == (time(hour=6), time(hour=9)) - assert m.range_of(TimeOfDay.Day) == (time(hour=9), time(hour=18)) - assert m.range_of(TimeOfDay.Dusk) == (time(hour=18), time(hour=20)) - assert m.range_of(TimeOfDay.Night) == (time(hour=0), time(hour=5)) - - -def test_best_guess_time_of_day_at() -> None: - night_at_midnight = DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=0), time(hour=5)), - ) - - assert night_at_midnight.best_guess_time_of_day_at(time(hour=0)) == TimeOfDay.Night - assert night_at_midnight.best_guess_time_of_day_at(time(hour=5)) == TimeOfDay.Night - assert night_at_midnight.best_guess_time_of_day_at(time(hour=6)) == TimeOfDay.Dawn - assert night_at_midnight.best_guess_time_of_day_at(time(hour=7)) == TimeOfDay.Dawn - assert night_at_midnight.best_guess_time_of_day_at(time(hour=9)) == TimeOfDay.Day - assert night_at_midnight.best_guess_time_of_day_at(time(hour=10)) == TimeOfDay.Day - assert night_at_midnight.best_guess_time_of_day_at(time(hour=18)) == TimeOfDay.Dusk - assert night_at_midnight.best_guess_time_of_day_at(time(hour=19)) == TimeOfDay.Dusk - - night_before_midnight = DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=22), time(hour=5)), - ) - - assert ( - night_before_midnight.best_guess_time_of_day_at(time(hour=0)) == TimeOfDay.Night - ) - assert ( - night_before_midnight.best_guess_time_of_day_at(time(hour=1)) == TimeOfDay.Night - ) - assert ( - night_before_midnight.best_guess_time_of_day_at(time(hour=22)) - == TimeOfDay.Night - ) - assert ( - night_before_midnight.best_guess_time_of_day_at(time(hour=23)) - == TimeOfDay.Night - ) - assert ( - night_before_midnight.best_guess_time_of_day_at(time(hour=6)) == TimeOfDay.Dawn - ) - - night_after_midnight = DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=2), time(hour=5)), - ) - - assert ( - night_after_midnight.best_guess_time_of_day_at(time(hour=0)) == TimeOfDay.Dusk - ) - assert ( - night_after_midnight.best_guess_time_of_day_at(time(hour=23)) == TimeOfDay.Dusk - ) - assert ( - night_after_midnight.best_guess_time_of_day_at(time(hour=2)) == TimeOfDay.Night - ) - assert ( - night_after_midnight.best_guess_time_of_day_at(time(hour=6)) == TimeOfDay.Dawn - ) - - -def test_whole_hours_only() -> None: - with pytest.raises(ValueError): - DaytimeMap( - dawn=(time(minute=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=2), time(hour=5)), - ) - with pytest.raises(ValueError): - DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(second=9), time(hour=18)), - dusk=(time(hour=18), time(hour=20)), - night=(time(hour=2), time(hour=5)), - ) - with pytest.raises(ValueError): - DaytimeMap( - dawn=(time(hour=6), time(hour=9)), - day=(time(hour=9), time(hour=18)), - dusk=(time(hour=18), time(microsecond=20)), - night=(time(hour=2), time(hour=5)), - ) diff --git a/tests/test_factions.py b/tests/test_factions.py deleted file mode 100644 index a8eaa7c64..000000000 --- a/tests/test_factions.py +++ /dev/null @@ -1,107 +0,0 @@ -import json -import unittest -from pathlib import Path - -import pytest -from dcs.helicopters import AH_64A, UH_1H -from dcs.planes import ( - AV8BNA, - A_10A, - A_10C, - A_10C_2, - B_1B, - B_52H, - E_2C, - E_3A, - FA_18C_hornet, - F_117A, - F_14B, - F_15C, - F_15E, - F_16C_50, - KC130, - KC_135, - MQ_9_Reaper, -) -from dcs.ships import LHA_Tarawa, Stennis -from dcs.vehicles import Armor, Artillery, Infantry, Unarmed - -from game.factions.faction import Faction - -THIS_DIR = Path(__file__).parent -RESOURCES_DIR = THIS_DIR / "resources" - - -class TestFactionLoader(unittest.TestCase): - def setUp(self) -> None: - pass - - @pytest.mark.skip(reason="Faction unit names in the json files are outdated") - def test_load_valid_faction(self) -> None: - with (RESOURCES_DIR / "valid_faction.json").open("r") as data: - faction = Faction.from_dict(json.load(data)) - - self.assertEqual(faction.country, "USA") - self.assertEqual(faction.name, "USA 2005") - self.assertEqual(faction.authors, "Khopa") - self.assertEqual(faction.description, "This is a test description") - - self.assertIn(F_15C, faction.aircrafts) - self.assertIn(F_15E, faction.aircrafts) - self.assertIn(F_14B, faction.aircrafts) - self.assertIn(FA_18C_hornet, faction.aircrafts) - self.assertIn(F_16C_50, faction.aircrafts) - self.assertIn(A_10A, faction.aircrafts) - self.assertIn(AV8BNA, faction.aircrafts) - self.assertIn(UH_1H, faction.aircrafts) - self.assertIn(AH_64A, faction.aircrafts) - self.assertIn(B_52H, faction.aircrafts) - self.assertIn(B_1B, faction.aircrafts) - self.assertIn(F_117A, faction.aircrafts) - self.assertIn(A_10C, faction.aircrafts) - self.assertIn(A_10C_2, faction.aircrafts) - - self.assertEqual(len(faction.awacs), 1) - self.assertIn(E_3A, faction.awacs) - self.assertIn(E_2C, faction.awacs) - - self.assertEqual(len(faction.tankers), 2) - self.assertIn(KC_135, faction.tankers) - self.assertIn(KC130, faction.tankers) - - self.assertTrue(faction.has_jtac) - self.assertEqual(faction.jtac_unit, MQ_9_Reaper) - - self.assertIn(Armor.M_1_Abrams, faction.frontline_units) - self.assertIn(Armor.M1134_Stryker_ATGM, faction.frontline_units) - self.assertIn(Armor.M1126_Stryker_ICV, faction.frontline_units) - self.assertIn(Armor.M_2_Bradley, faction.frontline_units) - self.assertIn(Armor.LAV_25, faction.frontline_units) - self.assertIn(Armor.M1043_HMMWV_Armament, faction.frontline_units) - self.assertIn(Armor.M1045_HMMWV_TOW, faction.frontline_units) - - self.assertIn(Artillery.MLRS, faction.artillery_units) - self.assertIn(Artillery.M_109, faction.artillery_units) - - self.assertIn(Unarmed.M_818, faction.logistics_units) - - self.assertIn(Infantry.Soldier_M4, faction.infantry_units) - self.assertIn(Infantry.Soldier_M249, faction.infantry_units) - - self.assertIn(Stennis.name, faction.naval_units) - self.assertIn(LHA_Tarawa.name, faction.naval_units) - - self.assertIn("mod", faction.requirements.keys()) - self.assertIn("Some mod is required", faction.requirements.values()) - - self.assertEqual(4, len(faction.carrier_names)) - self.assertEqual(5, len(faction.helicopter_carrier_names)) - - @pytest.mark.skip(reason="Faction unit names in the json files are outdated") - def test_load_valid_faction_with_invalid_country(self) -> None: - with (RESOURCES_DIR / "invalid_faction_country.json").open("r") as data: - try: - Faction.from_dict(json.load(data)) - self.fail("Should have thrown assertion error") - except AssertionError as e: - pass diff --git a/tests/test_pilot.py b/tests/test_pilot.py deleted file mode 100644 index 70b260f1e..000000000 --- a/tests/test_pilot.py +++ /dev/null @@ -1,65 +0,0 @@ -import pytest -from faker import Faker - -from game.squadrons.pilot import Pilot, PilotStatus - - -@pytest.fixture(scope="function") -def pilot() -> Pilot: - return Pilot("John Doe") - - -def test_pilot_creation() -> None: - new_pilot = Pilot("John Doe") - assert new_pilot.name == "John Doe" - assert new_pilot.status == PilotStatus.Active - - -def test_pilot_active(pilot: Pilot) -> None: - assert pilot.status == PilotStatus.Active - - -def test_pilot_alive(pilot: Pilot) -> None: - assert pilot.alive == True - - -def test_pilot_on_leave(pilot: Pilot) -> None: - pilot.send_on_leave() - assert pilot.status == PilotStatus.OnLeave - assert pilot.on_leave == True - pilot.return_from_leave() - assert pilot.status == PilotStatus.Active - # mypy thinks this line is unreachable. It isn't. - assert pilot.on_leave == False # type: ignore - - -def test_pilot_on_leave_twice(pilot: Pilot) -> None: - pilot.send_on_leave() - assert pilot.status == PilotStatus.OnLeave - with pytest.raises(RuntimeError): - pilot.send_on_leave() - - -def test_pilot_not_on_leave(pilot: Pilot) -> None: - with pytest.raises(RuntimeError): - pilot.return_from_leave() - - -def test_pilot_dead(pilot: Pilot) -> None: - pilot.kill() - assert pilot.status == PilotStatus.Dead - - -def test_pilot_record(pilot: Pilot) -> None: - pilot.record.missions_flown == 0 - - -def test_missions_flown(pilot: Pilot) -> None: - pilot.record.missions_flown = 1 - assert pilot.record.missions_flown == 1 - - -def test_random_pilot_name() -> None: - faker = Faker() - random_pilot = Pilot.random(faker) - assert random_pilot.name diff --git a/tests/test_radios.py b/tests/test_radios.py deleted file mode 100644 index 7ec061ca4..000000000 --- a/tests/test_radios.py +++ /dev/null @@ -1,36 +0,0 @@ -from typing import Callable - -import pytest - -from game.radio.radios import MHz, RadioFrequency, kHz - - -@pytest.mark.parametrize("units,factory", [("kHz", kHz), ("MHz", MHz)]) -def test_radio_parsing(units: str, factory: Callable[..., RadioFrequency]) -> None: - assert RadioFrequency.parse(f"0 {units}") == factory(0) - assert RadioFrequency.parse(f"0.0 {units}") == factory(0) - assert RadioFrequency.parse(f"255 {units}") == factory(255) - assert RadioFrequency.parse(f"255.5 {units}") == factory(255, 500) - assert RadioFrequency.parse(f"255.500 {units}") == factory(255, 500) - assert RadioFrequency.parse(f"255.050 {units}") == factory(255, 50) - assert RadioFrequency.parse(f"255.005 {units}") == factory(255, 5) - assert RadioFrequency.parse(f"255.0 {units}") == factory(255) - - with pytest.raises(ValueError): - RadioFrequency.parse("") - with pytest.raises(ValueError): - RadioFrequency.parse("255") - with pytest.raises(ValueError): - RadioFrequency.parse(f" 255 {units}") - with pytest.raises(ValueError): - RadioFrequency.parse(f"255 {units} ") - with pytest.raises(ValueError): - RadioFrequency.parse(f"255 {units.lower()}") - with pytest.raises(ValueError): - RadioFrequency.parse(f"255. {units}") - with pytest.raises(ValueError): - RadioFrequency.parse(f".0 {units}") - with pytest.raises(ValueError): - RadioFrequency.parse(f"0. {units}") - with pytest.raises(ValueError): - RadioFrequency.parse(f"255.5555 {units}") diff --git a/tests/test_sidc.py b/tests/test_sidc.py deleted file mode 100644 index 6c6fac368..000000000 --- a/tests/test_sidc.py +++ /dev/null @@ -1,17 +0,0 @@ -from game.sidc import ( - LandInstallationEntity, - StandardIdentity, - Status, - SymbolIdentificationCode, - SymbolSet, -) - - -def test_sidc() -> None: - sidc = SymbolIdentificationCode( - standard_identity=StandardIdentity.FRIEND, - symbol_set=SymbolSet.LAND_INSTALLATIONS, - status=Status.PRESENT_DAMAGED, - entity=LandInstallationEntity.AIPORT_AIR_BASE, - ) - assert str(sidc) == "10032030001213010000" diff --git a/tests/test_tacan.py b/tests/test_tacan.py deleted file mode 100644 index 0b1e4b239..000000000 --- a/tests/test_tacan.py +++ /dev/null @@ -1,101 +0,0 @@ -import pytest - -from game.radio.tacan import ( - OutOfTacanChannelsError, - TacanBand, - TacanChannel, - TacanRegistry, - TacanUsage, -) - -ALL_VALID_X_TR = [1, *range(31, 46 + 1), *range(64, 126 + 1)] -ALL_VALID_X_A2A = [*range(37, 63 + 1), *range(100, 126 + 1)] - - -def test_allocate_first_few_channels() -> None: - registry = TacanRegistry() - chan1 = registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - chan2 = registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - chan3 = registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - assert chan1 == TacanChannel(1, TacanBand.X) - assert chan2 == TacanChannel(31, TacanBand.X) - assert chan3 == TacanChannel(32, TacanBand.X) - - -def test_allocate_different_usages() -> None: - """Make sure unallocated channels for one use don't make channels unavailable for other usage""" - registry = TacanRegistry() - - chanA2AX = registry.alloc_for_band(TacanBand.X, TacanUsage.AirToAir) - chanA2AY = registry.alloc_for_band(TacanBand.Y, TacanUsage.AirToAir) - assert chanA2AX == TacanChannel(37, TacanBand.X) - assert chanA2AY == TacanChannel(37, TacanBand.Y) - - chanTRX = registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - chanTRY = registry.alloc_for_band(TacanBand.Y, TacanUsage.TransmitReceive) - assert chanTRX == TacanChannel(1, TacanBand.X) - assert chanTRY == TacanChannel(1, TacanBand.Y) - - -def test_reserve_all_valid_transmit_receive() -> None: - registry = TacanRegistry() - print("All valid x", ALL_VALID_X_TR) - - for num in ALL_VALID_X_TR: - registry.mark_unavailable(TacanChannel(num, TacanBand.X)) - - with pytest.raises(OutOfTacanChannelsError): - registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - - # Check that we still can allocate an a2a channel even - # though the T/R channels are used up - chanA2A = registry.alloc_for_band(TacanBand.X, TacanUsage.AirToAir) - assert chanA2A == TacanChannel(47, TacanBand.X) - - -def test_reserve_all_valid_a2a() -> None: - registry = TacanRegistry() - print("All valid x", ALL_VALID_X_A2A) - - for num in ALL_VALID_X_A2A: - registry.mark_unavailable(TacanChannel(num, TacanBand.X)) - - with pytest.raises(OutOfTacanChannelsError): - registry.alloc_for_band(TacanBand.X, TacanUsage.AirToAir) - - # Check that we still can allocate an a2a channel even - # though the T/R channels are used up - chanTR = registry.alloc_for_band(TacanBand.X, TacanUsage.TransmitReceive) - assert chanTR == TacanChannel(1, TacanBand.X) - - -def test_reserve_again() -> None: - registry = TacanRegistry() - registry.mark_unavailable(TacanChannel(1, TacanBand.X)) - registry.mark_unavailable(TacanChannel(1, TacanBand.X)) - - -def test_tacan_parsing() -> None: - assert TacanChannel.parse("1X") == TacanChannel(1, TacanBand.X) - assert TacanChannel.parse("1Y") == TacanChannel(1, TacanBand.Y) - assert TacanChannel.parse("10X") == TacanChannel(10, TacanBand.X) - assert TacanChannel.parse("100X") == TacanChannel(100, TacanBand.X) - - with pytest.raises(ValueError): - TacanChannel.parse("1000X") - with pytest.raises(ValueError): - TacanChannel.parse("0X") - with pytest.raises(ValueError): - TacanChannel.parse("1Z") - with pytest.raises(ValueError): - TacanChannel.parse("X") - with pytest.raises(ValueError): - TacanChannel.parse("1") - with pytest.raises(ValueError): - TacanChannel.parse("1 X") - with pytest.raises(ValueError): - TacanChannel.parse(" 1X") - with pytest.raises(ValueError): - TacanChannel.parse("1X ") - with pytest.raises(ValueError): - TacanChannel.parse("1x") diff --git a/tests/test_zipfileext.py b/tests/test_zipfileext.py deleted file mode 100644 index 8d34136a8..000000000 --- a/tests/test_zipfileext.py +++ /dev/null @@ -1,33 +0,0 @@ -from pathlib import Path -from zipfile import ZipFile - -import pytest - -from game.zipfileext import ZipFileExt - - -def test_remove_member_does_nothing_if_member_is_not_present(tmp_zip: Path) -> None: - expect_mtime = tmp_zip.stat().st_mtime - ZipFileExt.remove_member(tmp_zip, "c", missing_ok=True) - assert tmp_zip.stat().st_mtime == expect_mtime - - -def test_remove_member_raises_if_missing_not_ok(tmp_zip: Path) -> None: - with pytest.raises(ValueError): - ZipFileExt.remove_member(tmp_zip, "c") - - -def test_remove_member(tmp_zip: Path) -> None: - with ZipFile(tmp_zip, "w") as zip_file: - zip_file.writestr("a", "foo") - zip_file.writestr("b", "bar") - - ZipFileExt.remove_member(tmp_zip, "a") - - with ZipFile(tmp_zip, "r") as zip_file: - with pytest.raises(KeyError): - zip_file.read("a") - # Yes, we wrote a str, but ZipFile.read always returns bytes, and ZipFile.write - # requires an intermediate file. It's hard to write bytes, and hard to read str. - # This is all the single-byte range of UTF-8 anyway, so it doesn't matter. - assert zip_file.read("b") == b"bar" diff --git a/tests/theater/test_controlpoint.py b/tests/theater/test_controlpoint.py deleted file mode 100644 index b0a960ad4..000000000 --- a/tests/theater/test_controlpoint.py +++ /dev/null @@ -1,117 +0,0 @@ -import pytest -from typing import Any - -from dcs.terrain.terrain import Airport -from game.ato.flighttype import FlightType -from game.theater.controlpoint import Airfield, Carrier, Lha, OffMapSpawn, Fob - - -def test_mission_types_friendly(mocker: Any) -> None: - """ - Test the mission types that can be planned against friendly control points - """ - # Airfield - mocker.patch("game.theater.controlpoint.Airfield.is_friendly", return_value=True) - airport = Airport(None, None) # type: ignore - airport.name = "test" # required for Airfield.__init__ - airfield = Airfield(airport, theater=None, starts_blue=True) # type: ignore - mission_types = list(airfield.mission_types(for_player=True)) - assert len(mission_types) == 3 - assert FlightType.AEWC in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.BARCAP in mission_types - - # Carrier - mocker.patch("game.theater.controlpoint.Carrier.is_friendly", return_value=True) - carrier = Carrier(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(carrier.mission_types(for_player=True)) - assert len(mission_types) == 3 - assert FlightType.AEWC in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.BARCAP in mission_types - - # LHA - mocker.patch("game.theater.controlpoint.Lha.is_friendly", return_value=True) - lha = Lha(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(lha.mission_types(for_player=True)) - assert len(mission_types) == 3 - assert FlightType.AEWC in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.BARCAP in mission_types - - # Fob - mocker.patch("game.theater.controlpoint.Fob.is_friendly", return_value=True) - fob = Fob(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(fob.mission_types(for_player=True)) - assert len(mission_types) == 2 - assert FlightType.AEWC in mission_types - assert FlightType.BARCAP in mission_types - - # Off map spawn - mocker.patch("game.theater.controlpoint.OffMapSpawn.is_friendly", return_value=True) - off_map_spawn = OffMapSpawn(name="test", position=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(off_map_spawn.mission_types(for_player=True)) - assert len(mission_types) == 0 - - -def test_mission_types_enemy(mocker: Any) -> None: - """ - Test the mission types that can be planned against enemy control points - """ - # Airfield - mocker.patch("game.theater.controlpoint.Airfield.is_friendly", return_value=False) - airport = Airport(None, None) # type: ignore - airport.name = "test" # required for Airfield.__init__ - airfield = Airfield(airport, theater=None, starts_blue=True) # type: ignore - mission_types = list(airfield.mission_types(for_player=True)) - assert len(mission_types) == 8 - assert FlightType.OCA_AIRCRAFT in mission_types - assert FlightType.OCA_RUNWAY in mission_types - assert FlightType.AIR_ASSAULT in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - assert FlightType.REFUELING in mission_types - - # Carrier - mocker.patch("game.theater.controlpoint.Carrier.is_friendly", return_value=False) - carrier = Carrier(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(carrier.mission_types(for_player=True)) - assert len(mission_types) == 5 - assert FlightType.ANTISHIP in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - # LHA - mocker.patch("game.theater.controlpoint.Lha.is_friendly", return_value=False) - lha = Lha(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(lha.mission_types(for_player=True)) - assert len(mission_types) == 5 - assert FlightType.ANTISHIP in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - # Fob - mocker.patch("game.theater.controlpoint.Fob.is_friendly", return_value=False) - fob = Fob(name="test", at=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(fob.mission_types(for_player=True)) - assert len(mission_types) == 6 - assert FlightType.AIR_ASSAULT in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - assert FlightType.STRIKE in mission_types - - # Off map spawn - mocker.patch( - "game.theater.controlpoint.OffMapSpawn.is_friendly", return_value=False - ) - off_map_spawn = OffMapSpawn(name="test", position=None, theater=None, starts_blue=True) # type: ignore - mission_types = list(off_map_spawn.mission_types(for_player=True)) - assert len(mission_types) == 0 diff --git a/tests/theater/test_landmap.py b/tests/theater/test_landmap.py deleted file mode 100644 index 61a113ab1..000000000 --- a/tests/theater/test_landmap.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import pytest - -from shapely.geometry import MultiPolygon, Polygon - -from dcs.terrain.caucasus.caucasus import Caucasus -from game.theater import landmap - - -def test_miz() -> None: - """ - Test miz generation and loading - """ - test_map = landmap.Landmap( - inclusion_zones=MultiPolygon([Polygon([(0, 0), (0, 1), (1, 0)])]), - exclusion_zones=MultiPolygon([Polygon([(1, 1), (0, 1), (1, 0)])]), - sea_zones=MultiPolygon([Polygon([(0, 0), (0, 2), (1, 0)])]), - ) - test_filename = "test.miz" - landmap.to_miz(test_map, Caucasus(), test_filename) - assert os.path.isfile("test.miz") - loaded_map = landmap.from_miz("test.miz") - assert test_map.inclusion_zones.equals_exact( - loaded_map.inclusion_zones, tolerance=1e-6 - ) - assert test_map.sea_zones.equals_exact(loaded_map.sea_zones, tolerance=1e-6) - assert test_map.exclusion_zones.equals_exact( - loaded_map.exclusion_zones, tolerance=1e-6 - ) - - if os.path.isfile(test_filename): - os.remove(test_filename) diff --git a/tests/theater/test_theatergroundobject.py b/tests/theater/test_theatergroundobject.py deleted file mode 100644 index eabe72a7a..000000000 --- a/tests/theater/test_theatergroundobject.py +++ /dev/null @@ -1,205 +0,0 @@ -import pytest -from typing import Any - -from dcs.mapping import Point -from dcs.terrain import Terrain -from game.ato.flighttype import FlightType -from game.theater.presetlocation import PresetLocation -from game.theater.theatergroundobject import ( - BuildingGroundObject, - CarrierGroundObject, - LhaGroundObject, - MissileSiteGroundObject, - CoastalSiteGroundObject, - SamGroundObject, - VehicleGroupGroundObject, - EwrGroundObject, - ShipGroundObject, - IadsBuildingGroundObject, -) -from game.theater.controlpoint import OffMapSpawn -from game.utils import Heading - - -def test_mission_types_friendly(mocker: Any) -> None: - """ - Test the mission types that can be planned against friendly Theater Ground Objects - """ - # Set up dummy inputs - dummy_location = PresetLocation( - name="dummy_location", position=Point(0, 0, None), heading=Heading(0) # type: ignore - ) - dummy_control_point = OffMapSpawn( - name="dummy_control_point", - position=Point(0, 0, None), # type: ignore - theater=None, # type: ignore - starts_blue=True, - ) - - # Patch is_friendly as it's difficult to set up a proper ControlPoint - mocker.patch("game.theater.controlpoint.OffMapSpawn.is_friendly", return_value=True) - - for ground_object_type in [ - CarrierGroundObject, - LhaGroundObject, - MissileSiteGroundObject, - CoastalSiteGroundObject, - SamGroundObject, - VehicleGroupGroundObject, - EwrGroundObject, - ShipGroundObject, - ]: - ground_object = ground_object_type( # type: ignore - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(ground_object.mission_types(for_player=True)) - assert mission_types == [FlightType.BARCAP] - - for ground_object_type in [BuildingGroundObject, IadsBuildingGroundObject]: # type: ignore - ground_object = ground_object_type( # type: ignore - name="test", - category="ammo", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(ground_object.mission_types(for_player=True)) - assert mission_types == [FlightType.BARCAP] - - -def test_mission_types_enemy(mocker: Any) -> None: - """ - Test the mission types that can be planned against enemy Theater Ground Objects - """ - # Set up dummy inputs - dummy_location = PresetLocation( - name="dummy_location", position=Point(0, 0, None), heading=Heading(0) # type: ignore - ) - dummy_control_point = OffMapSpawn( - name="dummy_control_point", - position=Point(0, 0, None), # type: ignore - theater=None, # type: ignore - starts_blue=True, - ) - - # Patch is_friendly as it's difficult to set up a proper ControlPoint - mocker.patch( - "game.theater.controlpoint.OffMapSpawn.is_friendly", return_value=False - ) - - building = BuildingGroundObject( - name="test", - category="ammo", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(building.mission_types(for_player=False)) - assert len(mission_types) == 6 - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - iads_building = IadsBuildingGroundObject( - name="test", - category="ammo", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(iads_building.mission_types(for_player=False)) - assert len(mission_types) == 7 - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - assert FlightType.DEAD in mission_types - - for ground_object_type in [ - CarrierGroundObject, - LhaGroundObject, - ShipGroundObject, - ]: - ground_object = ground_object_type( # type: ignore - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(ground_object.mission_types(for_player=False)) - assert len(mission_types) == 7 - assert FlightType.ANTISHIP in mission_types - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - sam = SamGroundObject( - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(sam.mission_types(for_player=False)) - assert len(mission_types) == 8 - assert FlightType.DEAD in mission_types - assert FlightType.SEAD in mission_types - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - ewr = EwrGroundObject( - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(ewr.mission_types(for_player=False)) - assert len(mission_types) == 7 - assert FlightType.DEAD in mission_types - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - for ground_object_type in [ # type: ignore - CoastalSiteGroundObject, - MissileSiteGroundObject, - ]: - ground_object = ground_object_type( # type: ignore - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(ground_object.mission_types(for_player=False)) - assert len(mission_types) == 7 - assert FlightType.BAI in mission_types - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types - - vehicles = VehicleGroupGroundObject( - name="test", - location=dummy_location, - control_point=dummy_control_point, - ) - mission_types = list(vehicles.mission_types(for_player=False)) - assert len(mission_types) == 7 - assert FlightType.BAI in mission_types - assert FlightType.STRIKE in mission_types - assert FlightType.REFUELING in mission_types - assert FlightType.ESCORT in mission_types - assert FlightType.TARCAP in mission_types - assert FlightType.SEAD_ESCORT in mission_types - assert FlightType.SWEEP in mission_types diff --git a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.cpg b/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.dbf b/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.dbf deleted file mode 100644 index 75eb11ceb..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.prj b/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.prj deleted file mode 100644 index 849a10000..000000000 --- a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_21S",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",10000000.0],PARAMETER["Central_Meridian",-57.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shp b/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shp deleted file mode 100644 index 8a2256ef5..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shx b/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shx deleted file mode 100644 index 278f0d409..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/exclusion/SouthAtlantic_ExclusionV2_simplified_dissolved_UTM21S.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.cpg b/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.dbf b/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.dbf deleted file mode 100644 index b7a7df4af..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.prj b/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.prj deleted file mode 100644 index 849a10000..000000000 --- a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_21S",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",10000000.0],PARAMETER["Central_Meridian",-57.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shp b/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shp deleted file mode 100644 index 70cebd04a..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shx b/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shx deleted file mode 100644 index 71806df6a..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/land/Landarea_750mBuffer_v2fixed_UTM21S.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.cpg b/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.dbf b/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.dbf deleted file mode 100644 index 37c8c4ce9..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.prj b/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.prj deleted file mode 100644 index 849a10000..000000000 --- a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_21S",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",10000000.0],PARAMETER["Central_Meridian",-57.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shp b/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shp deleted file mode 100644 index f8aad0722..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shx b/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shx deleted file mode 100644 index 0f8178150..000000000 Binary files a/unshipped_data/arcgis_maps/falklands/sea/OSM_Sea_UTM21S_v3clipped_simplified1500buffered1500_mainseav2_ocean.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.cpg b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.dbf b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.dbf deleted file mode 100644 index 4f33c917f..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.prj b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.prj deleted file mode 100644 index a46c6c43e..000000000 --- a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_31N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",3.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.qmd b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.qmd deleted file mode 100644 index 95f437e6f..000000000 --- a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.qmd +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - dataset - - - - - - - - - PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]] - +proj=utm +zone=31 +datum=WGS84 +units=m +no_defs - 3115 - 32631 - EPSG:32631 - WGS 84 / UTM zone 31N - utm - EPSG:7030 - false - - - - diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shp b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shp deleted file mode 100644 index 550e0338b..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shx b/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shx deleted file mode 100644 index 8e029bca2..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/exclusion/NormandyExclusionAreav5.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.cpg b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.dbf b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.dbf deleted file mode 100644 index 4f33c917f..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.prj b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.prj deleted file mode 100644 index a46c6c43e..000000000 --- a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_31N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",3.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.qmd b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.qmd deleted file mode 100644 index 95f437e6f..000000000 --- a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.qmd +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - dataset - - - - - - - - - PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]] - +proj=utm +zone=31 +datum=WGS84 +units=m +no_defs - 3115 - 32631 - EPSG:32631 - WGS 84 / UTM zone 31N - utm - EPSG:7030 - false - - - - diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shp b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shp deleted file mode 100644 index d8ff09ffa..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shx b/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shx deleted file mode 100644 index 5895fc3d4..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/land/NormandyUsableLandv5.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.cpg b/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.dbf b/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.dbf deleted file mode 100644 index 9cfda9c41..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.prj b/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.prj deleted file mode 100644 index a46c6c43e..000000000 --- a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_31N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",3.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shp b/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shp deleted file mode 100644 index bad532c2f..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shx b/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shx deleted file mode 100644 index ae1c28772..000000000 Binary files a/unshipped_data/arcgis_maps/normandy/sea/NormandyOceanv2.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.cpg b/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.dbf b/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.dbf deleted file mode 100644 index 5c9803b1e..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.prj b/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.prj deleted file mode 100644 index 5fd2a625f..000000000 --- a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_37N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",39.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shp b/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shp deleted file mode 100644 index 2970f725d..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shx b/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shx deleted file mode 100644 index f1bf26441..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/exclusion/FinalExclusionArea.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.cpg b/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.dbf b/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.dbf deleted file mode 100644 index 5c9803b1e..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.prj b/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.prj deleted file mode 100644 index 5fd2a625f..000000000 --- a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_37N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",39.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shp b/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shp deleted file mode 100644 index 93ebfd991..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shx b/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shx deleted file mode 100644 index 6aaafc136..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/land/FinalUsableLand.shx and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.cpg b/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.cpg deleted file mode 100644 index 3ad133c04..000000000 --- a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.cpg +++ /dev/null @@ -1 +0,0 @@ -UTF-8 \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.dbf b/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.dbf deleted file mode 100644 index 5c9803b1e..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.dbf and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.prj b/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.prj deleted file mode 100644 index 5fd2a625f..000000000 --- a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.prj +++ /dev/null @@ -1 +0,0 @@ -PROJCS["WGS_1984_UTM_Zone_37N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",39.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] \ No newline at end of file diff --git a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shp b/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shp deleted file mode 100644 index 37902607b..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shp and /dev/null differ diff --git a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shx b/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shx deleted file mode 100644 index 74cd05df0..000000000 Binary files a/unshipped_data/arcgis_maps/sinai/sea/FinalOcean.shx and /dev/null differ diff --git a/unshipped_data/hit_points/.gitignore b/unshipped_data/hit_points/.gitignore deleted file mode 100644 index 5a4a8d9d9..000000000 --- a/unshipped_data/hit_points/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -hit_points_data.csv -hit_points_generator.miz \ No newline at end of file diff --git a/unshipped_data/hit_points/README.md b/unshipped_data/hit_points/README.md deleted file mode 100644 index bd10ceb86..000000000 --- a/unshipped_data/hit_points/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Hit Points Generator -The scripts in this folder creates/updates hit point data for units and static objects in DCS -and updates the unit YAML files in Liberation. - -# Usage - -1. Run *mission.py*, which will generate a DCS mission file *hit_points_generator.miz* in the -same folder as *mission.py*. -2. Run the mission *hit_points_generator.miz* in DCS, wait a few seconds and exit the mission. -This mission should generate a file *hit_points_data.csv* in the same folder as *mission.py*. -This mission requires the sanitizing of the Lua *io* module to be commented out in -MissionScripting.lua, but this should already be the case when running Liberation. -3. Run *update.py*, which will update the YAML files in Liberation's *resources* folder, adding -the hit_points data if it does not exist or overwriting it if it does. Note that *update.py* -will need to be updated if the file location with the Liberation code is changed. diff --git a/unshipped_data/hit_points/mission.py b/unshipped_data/hit_points/mission.py deleted file mode 100644 index 9cfab6e00..000000000 --- a/unshipped_data/hit_points/mission.py +++ /dev/null @@ -1,125 +0,0 @@ -import copy -import os -import typing - -from dcs import ( - action, - countries, - helicopters, - planes, - ships, - statics, - triggers, - unittype, - vehicles, -) -from dcs.country import Country -from dcs.mapping import Point, Vector2 -from dcs.mission import Mission -from dcs.terrain.caucasus import Caucasus -from dcs.translation import String, Translation - - -def add_units( - unit_class: str, - unit_map: dict[str, typing.Any], - origin: Point, - spacing: Vector2 = Vector2(0, 1000), - country_name: str = "USA", -) -> typing.Generator[dict[str, typing.Any], None, None]: - position = copy.deepcopy(origin) - country = mission.country(country_name) - for unit_name in unit_map.keys(): - unit_type = unit_map[unit_name] - position += spacing - yield { - "name": unit_class + "," + unit_name, - "_type": unit_type, - "position": position, - "country": country, - } - position = copy.deepcopy(position) - - -def handle_flying_unit(unit: dict[str, typing.Any], altitude: int) -> None: - unit["altitude"] = altitude - unit["aircraft_type"] = unit["_type"] - unit.pop("_type") - - -def setup_export_trigger( - mission: Mission, output_filename: str, script_file: str = "export.lua" -) -> None: - trigger_rule = triggers.TriggerStart(comment="Run export script") - script = f""" -local output_file = io.open('{output_filename}', 'w') -for i, group in pairs(coalition.getGroups(2)) do - for j, unit in pairs(group:getUnits()) do - output_file:write(group:getName(), ',', unit:getLife(), '\\n') - end -end -for i, static_object in pairs(coalition.getStaticObjects(2)) do - output_file:write(static_object:getName(), ',', static_object:getLife(), '\\n') -end -output_file:close() - """ - translation = Translation(mission) - script_string = String(_id=script, translation=translation) - script_string.set(script) - trigger_rule.add_action(action.DoScript(script_string)) - mission.triggerrules.triggers.append(trigger_rule) - - -if __name__ == "__main__": - output_path = os.path.dirname(__file__) - miz_output = os.path.join(output_path, "hit_points_generator.miz") - data_output = os.path.join(output_path, "hit_points_data.csv") - - terrain = Caucasus() - - mission = Mission(terrain=terrain) - mission.filename = miz_output - - # Add ships - for unit in add_units( - "ship", ships.ship_map, origin=Point(-200000, -300000, terrain) - ): - mission.ship_group(**unit) - - # Add statics - for unit in add_units( - "static", statics.fortification_map, origin=Point(-500000, -300000, terrain) - ): - mission.static_group(**unit) - for unit in add_units( - "static", statics.warehouse_map, origin=Point(-501000, -300000, terrain) - ): - mission.static_group(**unit) - - # Add vehicles - for unit in add_units( - "vehicle", vehicles.vehicle_map, origin=Point(-502000, -300000, terrain) - ): - mission.vehicle_group(**unit) - - # Add helicopters - for unit in add_units( - "helicopter", - helicopters.helicopter_map, - origin=Point(-210000, -300000, terrain), - ): - handle_flying_unit(unit, altitude=5000) - mission.flight_group_inflight(**unit) - - # Add planes - for unit in add_units( - "plane", planes.plane_map, origin=Point(-190000, -300000, terrain) - ): - if unit["name"].split(",")[1] in ["Mirage-F1JA"]: # skip problematic units - continue - handle_flying_unit(unit, altitude=10000) - mission.flight_group_inflight(**unit) - - setup_export_trigger(mission, output_filename=data_output.replace(os.sep, "//")) - - mission.save() diff --git a/unshipped_data/hit_points/update.py b/unshipped_data/hit_points/update.py deleted file mode 100644 index e1482b352..000000000 --- a/unshipped_data/hit_points/update.py +++ /dev/null @@ -1,56 +0,0 @@ -import csv -import os -import yaml - - -def update_yaml(file: str, hit_points: int) -> None: - with open(file, "r") as f: - data = f.readlines() - - # strip trailing whitespace - while not len(data[-1]) and len(data) > 0: - data = data[0:-1] - - # append trailing newline - if data[-1][-1] != "\n": - data[-1] += "\n" - - # update, ignore existing hit_points settings - found = False - key = "hit_points" - for line in data: - if line[0 : len(key) + 1] == f"{key}:": - line = f"{key}: {hit_points}\n" - found = True - if not found: - data.append(f"{key}: {hit_points}\n") - - with open(file, "w") as f: - f.writelines(data) - - -if __name__ == "__main__": - hit_points_file = os.path.join(os.path.dirname(__file__), "hit_points_data.csv") - - resources_path = os.path.join(os.path.dirname(__file__), "..", "..", "resources") - resource_type_paths = { - "ship": "units\\ships", - "helicopter": "units\\aircraft", - "plane": "units\\aircraft", - "vehicle": "units\\ground_units", - } - - with open(hit_points_file, "r") as file: - reader = csv.DictReader(file, fieldnames=["type", "name", "hit_points"]) - for line in reader: - if line["type"] not in resource_type_paths: - continue - yaml_file = os.path.join( - resources_path, - resource_type_paths[line["type"]], - f"{line['name']}.yaml", - ) - if not os.path.exists(yaml_file): - print(f"Skipping {line['name']} as YAML file could not be found") - continue - update_yaml(yaml_file, int(float(line["hit_points"])))